summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-09-24 10:31:34 +0200
committerIngo Molnar <mingo@elte.hu>2008-09-24 10:31:34 +0200
commite6aa0f07cb5e81a7cbeaf3be6e2101234c2f0d30 (patch)
tree77926550ac0c31b1423bcf193a4ed0ecb7fda2c1 /drivers/net/wireless
parentd4738792fb86600b6cb7220459d9c47e819b3580 (diff)
parent72d31053f62c4bc464c2783974926969614a8649 (diff)
Merge commit 'v2.6.27-rc7' into x86/microcode
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/Kconfig2
-rw-r--r--drivers/net/wireless/Makefile1
-rw-r--r--drivers/net/wireless/ath5k/ath5k.h8
-rw-r--r--drivers/net/wireless/ath5k/base.c120
-rw-r--r--drivers/net/wireless/ath5k/base.h3
-rw-r--r--drivers/net/wireless/ath5k/debug.c2
-rw-r--r--drivers/net/wireless/ath5k/debug.h1
-rw-r--r--drivers/net/wireless/ath5k/hw.c243
-rw-r--r--drivers/net/wireless/ath5k/initvals.c4
-rw-r--r--drivers/net/wireless/ath5k/phy.c185
-rw-r--r--drivers/net/wireless/ath5k/reg.h934
-rw-r--r--drivers/net/wireless/ath9k/Kconfig8
-rw-r--r--drivers/net/wireless/ath9k/Makefile11
-rw-r--r--drivers/net/wireless/ath9k/ath9k.h1021
-rw-r--r--drivers/net/wireless/ath9k/beacon.c992
-rw-r--r--drivers/net/wireless/ath9k/core.c1923
-rw-r--r--drivers/net/wireless/ath9k/core.h1073
-rw-r--r--drivers/net/wireless/ath9k/hw.c8575
-rw-r--r--drivers/net/wireless/ath9k/hw.h969
-rw-r--r--drivers/net/wireless/ath9k/initvals.h3146
-rw-r--r--drivers/net/wireless/ath9k/main.c1494
-rw-r--r--drivers/net/wireless/ath9k/phy.c436
-rw-r--r--drivers/net/wireless/ath9k/phy.h543
-rw-r--r--drivers/net/wireless/ath9k/rc.c2126
-rw-r--r--drivers/net/wireless/ath9k/rc.h316
-rw-r--r--drivers/net/wireless/ath9k/recv.c1319
-rw-r--r--drivers/net/wireless/ath9k/reg.h1385
-rw-r--r--drivers/net/wireless/ath9k/regd.c1026
-rw-r--r--drivers/net/wireless/ath9k/regd.h412
-rw-r--r--drivers/net/wireless/ath9k/regd_common.h1915
-rw-r--r--drivers/net/wireless/ath9k/xmit.c2871
-rw-r--r--drivers/net/wireless/atmel.c51
-rw-r--r--drivers/net/wireless/b43/main.c6
-rw-r--r--drivers/net/wireless/b43/rfkill.c18
-rw-r--r--drivers/net/wireless/b43/xmit.c2
-rw-r--r--drivers/net/wireless/b43legacy/main.c6
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.c18
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c2
-rw-r--r--drivers/net/wireless/ipw2100.c4
-rw-r--r--drivers/net/wireless/ipw2200.c8
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig98
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c34
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c165
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c86
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c (renamed from drivers/net/wireless/iwlwifi/iwl-4965-rs.c)330
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h (renamed from drivers/net/wireless/iwlwifi/iwl-4965-rs.h)23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c (renamed from drivers/net/wireless/iwlwifi/iwl4965-base.c)272
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h44
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c88
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h15
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c74
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c46
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h33
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rfkill.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c64
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c147
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c70
-rw-r--r--drivers/net/wireless/libertas/if_cs.c13
-rw-r--r--drivers/net/wireless/libertas/main.c15
-rw-r--r--drivers/net/wireless/libertas/persistcfg.c30
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c2
-rw-r--r--drivers/net/wireless/orinoco.c17
-rw-r--r--drivers/net/wireless/p54/p54.h2
-rw-r--r--drivers/net/wireless/p54/p54common.c75
-rw-r--r--drivers/net/wireless/p54/p54common.h18
-rw-r--r--drivers/net/wireless/p54/p54usb.c10
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c33
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c17
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c7
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h7
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c84
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c37
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h10
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h5
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c33
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h22
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c56
-rw-r--r--drivers/net/wireless/rtl8187.h15
-rw-r--r--drivers/net/wireless/rtl8187_dev.c111
-rw-r--r--drivers/net/wireless/wavelan.c3
-rw-r--r--drivers/net/wireless/wavelan_cs.c6
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c1
101 files changed, 34006 insertions, 1543 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 91fc2c765d9..9931b5ab59c 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -649,6 +649,7 @@ config RTL8187
Trendnet TEW-424UB
ASUS P5B Deluxe
Toshiba Satellite Pro series of laptops
+ Asus Wireless Link
Thanks to Realtek for their support!
@@ -694,6 +695,7 @@ config MAC80211_HWSIM
source "drivers/net/wireless/p54/Kconfig"
source "drivers/net/wireless/ath5k/Kconfig"
+source "drivers/net/wireless/ath9k/Kconfig"
source "drivers/net/wireless/iwlwifi/Kconfig"
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/b43/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 54a4f6f1db6..59aa89ec6e8 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -62,5 +62,6 @@ obj-$(CONFIG_RT2X00) += rt2x00/
obj-$(CONFIG_P54_COMMON) += p54/
obj-$(CONFIG_ATH5K) += ath5k/
+obj-$(CONFIG_ATH9K) += ath9k/
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h
index ba35c30d203..9102eea3c8b 100644
--- a/drivers/net/wireless/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath5k/ath5k.h
@@ -186,11 +186,13 @@ struct ath5k_srev_name {
#define AR5K_SREV_RAD_2111 0x20
#define AR5K_SREV_RAD_5112 0x30
#define AR5K_SREV_RAD_5112A 0x35
+#define AR5K_SREV_RAD_5112B 0x36
#define AR5K_SREV_RAD_2112 0x40
#define AR5K_SREV_RAD_2112A 0x45
-#define AR5K_SREV_RAD_SC0 0x56 /* Found on 2413/2414 */
-#define AR5K_SREV_RAD_SC1 0x63 /* Found on 5413/5414 */
-#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424-5/5424 */
+#define AR5K_SREV_RAD_2112B 0x46
+#define AR5K_SREV_RAD_SC0 0x50 /* Found on 2413/2414 */
+#define AR5K_SREV_RAD_SC1 0x60 /* Found on 5413/5414 */
+#define AR5K_SREV_RAD_SC2 0xa0 /* Found on 2424-5/5424 */
#define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */
/* IEEE defs */
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index d9769c52734..0676c6d8438 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -40,10 +40,11 @@
*
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/hardirq.h>
#include <linux/if.h>
+#include <linux/io.h>
#include <linux/netdevice.h>
#include <linux/cache.h>
#include <linux/pci.h>
@@ -93,8 +94,6 @@ static struct pci_device_id ath5k_pci_id_table[] __devinitdata = {
{ PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */
{ PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */
{ PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* 5424 Condor (PCI-E)*/
- { PCI_VDEVICE(ATHEROS, 0x0023), .driver_data = AR5K_AR5212 }, /* 5416 */
- { PCI_VDEVICE(ATHEROS, 0x0024), .driver_data = AR5K_AR5212 }, /* 5418 */
{ 0 }
};
MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
@@ -252,7 +251,7 @@ static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
return;
pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len,
PCI_DMA_TODEVICE);
- dev_kfree_skb(bf->skb);
+ dev_kfree_skb_any(bf->skb);
bf->skb = NULL;
}
@@ -467,13 +466,11 @@ ath5k_pci_probe(struct pci_dev *pdev,
mutex_init(&sc->lock);
spin_lock_init(&sc->rxbuflock);
spin_lock_init(&sc->txbuflock);
+ spin_lock_init(&sc->block);
/* Set private data */
pci_set_drvdata(pdev, hw);
- /* Enable msi for devices that support it */
- pci_enable_msi(pdev);
-
/* Setup interrupt handler */
ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
if (ret) {
@@ -551,7 +548,6 @@ err_ah:
err_irq:
free_irq(pdev->irq, sc);
err_free:
- pci_disable_msi(pdev);
ieee80211_free_hw(hw);
err_map:
pci_iounmap(pdev, mem);
@@ -573,7 +569,6 @@ ath5k_pci_remove(struct pci_dev *pdev)
ath5k_detach(pdev, hw);
ath5k_hw_detach(sc->ah);
free_irq(pdev->irq, sc);
- pci_disable_msi(pdev);
pci_iounmap(pdev, sc->iobase);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
@@ -590,6 +585,8 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
ath5k_led_off(sc);
ath5k_stop_hw(sc);
+
+ free_irq(pdev->irq, sc);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
@@ -605,15 +602,12 @@ ath5k_pci_resume(struct pci_dev *pdev)
struct ath5k_hw *ah = sc->ah;
int i, err;
- err = pci_set_power_state(pdev, PCI_D0);
- if (err)
- return err;
+ pci_restore_state(pdev);
err = pci_enable_device(pdev);
if (err)
return err;
- pci_restore_state(pdev);
/*
* Suspend/Resume resets the PCI configuration space, so we have to
* re-disable the RETRY_TIMEOUT register (0x41) to keep
@@ -621,7 +615,15 @@ ath5k_pci_resume(struct pci_dev *pdev)
*/
pci_write_config_byte(pdev, 0x41, 0);
- ath5k_init(sc);
+ err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
+ if (err) {
+ ATH5K_ERR(sc, "request_irq failed\n");
+ goto err_no_irq;
+ }
+
+ err = ath5k_init(sc);
+ if (err)
+ goto err_irq;
ath5k_led_enable(sc);
/*
@@ -635,6 +637,11 @@ ath5k_pci_resume(struct pci_dev *pdev)
ath5k_hw_reset_key(ah, i);
return 0;
+err_irq:
+ free_irq(pdev->irq, sc);
+err_no_irq:
+ pci_disable_device(pdev);
+ return err;
}
#endif /* CONFIG_PM */
@@ -1224,7 +1231,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
pktlen = skb->len;
- if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT)) {
+ if (info->control.hw_key) {
keyidx = info->control.hw_key->hw_key_idx;
pktlen += info->control.icv_len;
}
@@ -1249,6 +1256,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
txq->link = &ds->ds_link;
ath5k_hw_tx_start(ah, txq->qnum);
+ mmiowb();
spin_unlock_bh(&txq->lock);
return 0;
@@ -1583,7 +1591,6 @@ ath5k_rx_stop(struct ath5k_softc *sc)
ath5k_hw_stop_pcu_recv(ah); /* disable PCU */
ath5k_hw_set_rx_filter(ah, 0); /* clear recv filter */
ath5k_hw_stop_rx_dma(ah); /* disable DMA engine */
- mdelay(3); /* 3ms is long enough for 1 frame */
ath5k_debug_printrxbuffs(sc, ah);
@@ -1682,31 +1689,44 @@ ath5k_tasklet_rx(unsigned long data)
struct ath5k_rx_status rs = {};
struct sk_buff *skb;
struct ath5k_softc *sc = (void *)data;
- struct ath5k_buf *bf;
+ struct ath5k_buf *bf, *bf_last;
struct ath5k_desc *ds;
int ret;
int hdrlen;
int pad;
spin_lock(&sc->rxbuflock);
+ if (list_empty(&sc->rxbuf)) {
+ ATH5K_WARN(sc, "empty rx buf pool\n");
+ goto unlock;
+ }
+ bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list);
do {
rxs.flag = 0;
- if (unlikely(list_empty(&sc->rxbuf))) {
- ATH5K_WARN(sc, "empty rx buf pool\n");
- break;
- }
bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
BUG_ON(bf->skb == NULL);
skb = bf->skb;
ds = bf->desc;
- /* TODO only one segment */
- pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
- sc->desc_len, PCI_DMA_FROMDEVICE);
-
- if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */
- break;
+ /*
+ * last buffer must not be freed to ensure proper hardware
+ * function. When the hardware finishes also a packet next to
+ * it, we are sure, it doesn't use it anymore and we can go on.
+ */
+ if (bf_last == bf)
+ bf->flags |= 1;
+ if (bf->flags) {
+ struct ath5k_buf *bf_next = list_entry(bf->list.next,
+ struct ath5k_buf, list);
+ ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc,
+ &rs);
+ if (ret)
+ break;
+ bf->flags &= ~1;
+ /* skip the overwritten one (even status is martian) */
+ goto next;
+ }
ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
if (unlikely(ret == -EINPROGRESS))
@@ -1752,8 +1772,6 @@ ath5k_tasklet_rx(unsigned long data)
goto next;
}
accept:
- pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr,
- rs.rs_datalen, PCI_DMA_FROMDEVICE);
pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize,
PCI_DMA_FROMDEVICE);
bf->skb = NULL;
@@ -1816,6 +1834,7 @@ accept:
next:
list_move_tail(&bf->list, &sc->rxbuf);
} while (ath5k_rxbuf_setup(sc, bf) == 0);
+unlock:
spin_unlock(&sc->rxbuflock);
}
@@ -1840,9 +1859,6 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
list_for_each_entry_safe(bf, bf0, &txq->q, list) {
ds = bf->desc;
- /* TODO only one segment */
- pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
- sc->desc_len, PCI_DMA_FROMDEVICE);
ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
if (unlikely(ret == -EINPROGRESS))
break;
@@ -2015,8 +2031,6 @@ ath5k_beacon_send(struct ath5k_softc *sc)
ATH5K_WARN(sc, "beacon queue %u didn't stop?\n", sc->bhalq);
/* NB: hw still stops DMA, so proceed */
}
- pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, bf->skb->len,
- PCI_DMA_TODEVICE);
ath5k_hw_put_tx_buf(ah, sc->bhalq, bf->daddr);
ath5k_hw_tx_start(ah, sc->bhalq);
@@ -2150,6 +2164,7 @@ ath5k_beacon_config(struct ath5k_softc *sc)
ath5k_hw_set_intr(ah, 0);
sc->bmisscount = 0;
+ sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
if (sc->opmode == IEEE80211_IF_TYPE_STA) {
sc->imask |= AR5K_INT_BMISS;
@@ -2165,8 +2180,11 @@ ath5k_beacon_config(struct ath5k_softc *sc)
sc->imask |= AR5K_INT_SWBA;
- if (ath5k_hw_hasveol(ah))
+ if (ath5k_hw_hasveol(ah)) {
+ spin_lock(&sc->block);
ath5k_beacon_send(sc);
+ spin_unlock(&sc->block);
+ }
}
/* TODO else AP */
@@ -2240,6 +2258,7 @@ ath5k_init(struct ath5k_softc *sc)
ret = 0;
done:
+ mmiowb();
mutex_unlock(&sc->lock);
return ret;
}
@@ -2272,6 +2291,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
if (!test_bit(ATH_STAT_INVALID, sc->status)) {
ath5k_led_off(sc);
ath5k_hw_set_intr(ah, 0);
+ synchronize_irq(sc->pdev->irq);
}
ath5k_txq_cleanup(sc);
if (!test_bit(ATH_STAT_INVALID, sc->status)) {
@@ -2321,9 +2341,13 @@ ath5k_stop_hw(struct ath5k_softc *sc)
}
}
ath5k_txbuf_free(sc, sc->bbuf);
+ mmiowb();
mutex_unlock(&sc->lock);
del_timer_sync(&sc->calib_tim);
+ tasklet_kill(&sc->rxtq);
+ tasklet_kill(&sc->txtq);
+ tasklet_kill(&sc->restq);
return ret;
}
@@ -2383,7 +2407,9 @@ ath5k_intr(int irq, void *dev_id)
TSF_TO_TU(tsf),
(unsigned long long) tsf);
} else {
+ spin_lock(&sc->block);
ath5k_beacon_send(sc);
+ spin_unlock(&sc->block);
}
}
if (status & AR5K_INT_RXEOL) {
@@ -2550,8 +2576,6 @@ ath5k_init_leds(struct ath5k_softc *sc)
struct pci_dev *pdev = sc->pdev;
char name[ATH5K_LED_MAX_NAME_LEN + 1];
- sc->led_on = 0; /* active low */
-
/*
* Auto-enable soft led processing for IBM cards and for
* 5211 minipci cards.
@@ -2560,11 +2584,13 @@ ath5k_init_leds(struct ath5k_softc *sc)
pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) {
__set_bit(ATH_STAT_LEDSOFT, sc->status);
sc->led_pin = 0;
+ sc->led_on = 0; /* active low */
}
/* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */
if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) {
__set_bit(ATH_STAT_LEDSOFT, sc->status);
sc->led_pin = 1;
+ sc->led_on = 1; /* active high */
}
if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
goto out;
@@ -2725,6 +2751,11 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
ret = -EOPNOTSUPP;
goto end;
}
+
+ /* Set to a reasonable value. Note that this will
+ * be set to mac80211's value at ath5k_config(). */
+ sc->bintval = 1000;
+
ret = 0;
end:
mutex_unlock(&sc->lock);
@@ -2769,9 +2800,6 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ath5k_hw *ah = sc->ah;
int ret;
- /* Set to a reasonable value. Note that this will
- * be set to mac80211's value at ath5k_config(). */
- sc->bintval = 1000;
mutex_lock(&sc->lock);
if (sc->vif != vif) {
ret = -EIO;
@@ -2783,6 +2811,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
/* XXX: assoc id is set to 0 for now, mac80211 doesn't have
* a clean way of letting us retrieve this yet. */
ath5k_hw_set_associd(ah, ah->ah_bssid, 0);
+ mmiowb();
}
if (conf->changed & IEEE80211_IFCC_BEACON &&
@@ -2971,6 +3000,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
}
unlock:
+ mmiowb();
mutex_unlock(&sc->lock);
return ret;
}
@@ -3028,27 +3058,29 @@ static int
ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath5k_softc *sc = hw->priv;
+ unsigned long flags;
int ret;
ath5k_debug_dump_skb(sc, skb, "BC ", 1);
- mutex_lock(&sc->lock);
-
if (sc->opmode != IEEE80211_IF_TYPE_IBSS) {
ret = -EIO;
goto end;
}
+ spin_lock_irqsave(&sc->block, flags);
ath5k_txbuf_free(sc, sc->bbuf);
sc->bbuf->skb = skb;
ret = ath5k_beacon_setup(sc, sc->bbuf);
if (ret)
sc->bbuf->skb = NULL;
- else
+ spin_unlock_irqrestore(&sc->block, flags);
+ if (!ret) {
ath5k_beacon_config(sc);
+ mmiowb();
+ }
end:
- mutex_unlock(&sc->lock);
return ret;
}
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 47f414b09e6..7ec2f377d5c 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -56,7 +56,7 @@
struct ath5k_buf {
struct list_head list;
- unsigned int flags; /* tx descriptor flags */
+ unsigned int flags; /* rx descriptor flags */
struct ath5k_desc *desc; /* virtual addr of desc */
dma_addr_t daddr; /* physical addr of desc */
struct sk_buff *skb; /* skbuff for buf */
@@ -172,6 +172,7 @@ struct ath5k_softc {
struct tasklet_struct txtq; /* tx intr tasklet */
struct ath5k_led tx_led; /* tx led */
+ spinlock_t block; /* protects beacon */
struct ath5k_buf *bbuf; /* beacon buffer */
unsigned int bhalq, /* SW q for outgoing beacons */
bmisscount, /* missed beacon transmits */
diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c
index 41d5fa34b54..6fa6c8e04ff 100644
--- a/drivers/net/wireless/ath5k/debug.c
+++ b/drivers/net/wireless/ath5k/debug.c
@@ -129,7 +129,7 @@ static struct reg regs[] = {
REG_STRUCT_INIT(AR5K_CPC1),
REG_STRUCT_INIT(AR5K_CPC2),
REG_STRUCT_INIT(AR5K_CPC3),
- REG_STRUCT_INIT(AR5K_CPCORN),
+ REG_STRUCT_INIT(AR5K_CPCOVF),
REG_STRUCT_INIT(AR5K_RESET_CTL),
REG_STRUCT_INIT(AR5K_SLEEP_CTL),
REG_STRUCT_INIT(AR5K_INTPEND),
diff --git a/drivers/net/wireless/ath5k/debug.h b/drivers/net/wireless/ath5k/debug.h
index 2cf8d18b10e..ffc52939330 100644
--- a/drivers/net/wireless/ath5k/debug.h
+++ b/drivers/net/wireless/ath5k/debug.h
@@ -63,7 +63,6 @@
struct ath5k_softc;
struct ath5k_hw;
-struct ieee80211_hw_mode;
struct sk_buff;
struct ath5k_buf;
diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c
index c6d12c53bda..ad1a5b422c8 100644
--- a/drivers/net/wireless/ath5k/hw.c
+++ b/drivers/net/wireless/ath5k/hw.c
@@ -139,6 +139,8 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
for (c = 0; c < 2; c++) {
cur_reg = regs[c];
+
+ /* Save previous value */
init_val = ath5k_hw_reg_read(ah, cur_reg);
for (i = 0; i < 256; i++) {
@@ -170,6 +172,10 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
var_pattern = 0x003b080f;
ath5k_hw_reg_write(ah, var_pattern, cur_reg);
}
+
+ /* Restore previous value */
+ ath5k_hw_reg_write(ah, init_val, cur_reg);
+
}
return 0;
@@ -287,67 +293,42 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
/* Identify the radio chip*/
if (ah->ah_version == AR5K_AR5210) {
ah->ah_radio = AR5K_RF5110;
+ /*
+ * Register returns 0x0/0x04 for radio revision
+ * so ath5k_hw_radio_revision doesn't parse the value
+ * correctly. For now we are based on mac's srev to
+ * identify RF2425 radio.
+ */
+ } else if (srev == AR5K_SREV_VER_AR2425) {
+ ah->ah_radio = AR5K_RF2425;
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) {
ah->ah_radio = AR5K_RF5111;
ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111;
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) {
-
ah->ah_radio = AR5K_RF5112;
-
- if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) {
- ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
- } else {
- ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
- }
-
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
ah->ah_radio = AR5K_RF2413;
- ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) {
ah->ah_radio = AR5K_RF5413;
- ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) {
-
/* AR5424 */
if (srev >= AR5K_SREV_VER_AR5424) {
ah->ah_radio = AR5K_RF5413;
- ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5424;
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
/* AR2424 */
} else {
ah->ah_radio = AR5K_RF2413; /* For testing */
- ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
+ ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
}
-
- /*
- * Register returns 0x4 for radio revision
- * so ath5k_hw_radio_revision doesn't parse the value
- * correctly. For now we are based on mac's srev to
- * identify RF2425 radio.
- */
- } else if (srev == AR5K_SREV_VER_AR2425) {
- ah->ah_radio = AR5K_RF2425;
- ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
}
-
ah->ah_phy = AR5K_PHY(0);
/*
- * Identify AR5212-based PCI-E cards
- * And write some initial settings.
- *
- * (doing a "strings" on ndis driver
- * -ar5211.sys- reveals the following
- * pci-e related functions:
- *
- * pcieClockReq
- * pcieRxErrNotify
- * pcieL1SKPEnable
- * pcieAspm
- * pcieDisableAspmOnRfWake
- * pciePowerSaveEnable
- *
- * I guess these point to ClockReq but
- * i'm not sure.)
+ * Write PCI-E power save settings
*/
if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080);
@@ -369,10 +350,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
if (ret)
goto err_free;
+ /* Write AR5K_PCICFG_UNK on 2112B and later chips */
+ if (ah->ah_radio_5ghz_revision > AR5K_SREV_RAD_2112B ||
+ srev > AR5K_SREV_VER_AR2413) {
+ ath5k_hw_reg_write(ah, AR5K_PCICFG_UNK, AR5K_PCICFG);
+ }
+
/*
* Get card capabilities, values, ...
*/
-
ret = ath5k_eeprom_init(ah);
if (ret) {
ATH5K_ERR(sc, "unable to init EEPROM\n");
@@ -843,27 +829,41 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
* Write some more initial register settings
*/
if (ah->ah_version == AR5K_AR5212) {
- ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11));
+ ath5k_hw_reg_write(ah, 0x0002a002, 0x982c);
if (channel->hw_value == CHANNEL_G)
if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413)
ath5k_hw_reg_write(ah, 0x00f80d80,
- AR5K_PHY(83));
+ 0x994c);
else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424)
ath5k_hw_reg_write(ah, 0x00380140,
- AR5K_PHY(83));
+ 0x994c);
else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425)
ath5k_hw_reg_write(ah, 0x00fc0ec0,
- AR5K_PHY(83));
+ 0x994c);
else /* 2425 */
ath5k_hw_reg_write(ah, 0x00fc0fc0,
- AR5K_PHY(83));
+ 0x994c);
else
- ath5k_hw_reg_write(ah, 0x00000000,
- AR5K_PHY(83));
-
- ath5k_hw_reg_write(ah, 0x000009b5, 0xa228);
- ath5k_hw_reg_write(ah, 0x0000000f, 0x8060);
+ ath5k_hw_reg_write(ah, 0x00000000, 0x994c);
+
+ /* Some bits are disabled here, we know nothing about
+ * register 0xa228 yet, most of the times this ends up
+ * with a value 0x9b5 -haven't seen any dump with
+ * a different value- */
+ /* Got this from decompiling binary HAL */
+ data = ath5k_hw_reg_read(ah, 0xa228);
+ data &= 0xfffffdff;
+ ath5k_hw_reg_write(ah, data, 0xa228);
+
+ data = ath5k_hw_reg_read(ah, 0xa228);
+ data &= 0xfffe03ff;
+ ath5k_hw_reg_write(ah, data, 0xa228);
+ data = 0;
+
+ /* Just write 0x9b5 ? */
+ /* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */
+ ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
ath5k_hw_reg_write(ah, 0x00000000, 0xa254);
ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL);
}
@@ -879,6 +879,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
else
data = 0xffb80d20;
ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
+ data = 0;
}
/*
@@ -898,7 +899,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
/*
* Write RF registers
- * TODO:Does this work on 5211 (5111) ?
*/
ret = ath5k_hw_rfregs(ah, channel, mode);
if (ret)
@@ -935,7 +935,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
return ret;
/* Set antenna mode */
- AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x44),
+ AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL,
ah->ah_antenna[ee_mode][0], 0xfffffc06);
/*
@@ -965,15 +965,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
ath5k_hw_reg_write(ah,
AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
- AR5K_PHY(0x5a));
+ AR5K_PHY_NFTHRES);
- AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x11),
+ AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING,
(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
0xffffc07f);
- AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x12),
+ AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN,
(ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
0xfffc0fff);
- AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x14),
+ AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00),
0xffff0000);
@@ -982,13 +982,13 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
- (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY(0x0d));
+ (ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
- AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x0a),
+ AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3,
ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
- AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x19),
+ AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF,
(ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
- AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x49), 4, 0xffffff01);
+ AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01);
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
AR5K_PHY_IQ_CORR_ENABLE |
@@ -1063,7 +1063,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
/*
- * 5111/5112 Specific
+ * On 5211+ read activation -> rx delay
+ * and use it.
*/
if (ah->ah_version != AR5K_AR5210) {
data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
@@ -1071,40 +1072,77 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
data = (channel->hw_value & CHANNEL_CCK) ?
((data << 2) / 22) : (data / 10);
- udelay(100 + data);
+ udelay(100 + (2 * data));
+ data = 0;
} else {
mdelay(1);
}
/*
- * Enable calibration and wait until completion
+ * Perform ADC test (?)
+ */
+ data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
+ ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
+ for (i = 0; i <= 20; i++) {
+ if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
+ break;
+ udelay(200);
+ }
+ ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1);
+ data = 0;
+
+ /*
+ * Start automatic gain calibration
+ *
+ * During AGC calibration RX path is re-routed to
+ * a signal detector so we don't receive anything.
+ *
+ * This method is used to calibrate some static offsets
+ * used together with on-the fly I/Q calibration (the
+ * one performed via ath5k_hw_phy_calibrate), that doesn't
+ * interrupt rx path.
+ *
+ * If we are in a noisy environment AGC calibration may time
+ * out.
*/
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
AR5K_PHY_AGCCTL_CAL);
+ /* At the same time start I/Q calibration for QAM constellation
+ * -no need for CCK- */
+ ah->ah_calibration = false;
+ if (!(mode == AR5K_MODE_11B)) {
+ ah->ah_calibration = true;
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+ AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+ AR5K_PHY_IQ_RUN);
+ }
+
+ /* Wait for gain calibration to finish (we check for I/Q calibration
+ * during ath5k_phy_calibrate) */
if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
AR5K_PHY_AGCCTL_CAL, 0, false)) {
- ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n",
+ ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
channel->center_freq);
return -EAGAIN;
}
+ /*
+ * Start noise floor calibration
+ *
+ * If we run NF calibration before AGC, it always times out.
+ * Binary HAL starts NF and AGC calibration at the same time
+ * and only waits for AGC to finish. I believe that's wrong because
+ * during NF calibration, rx path is also routed to a detector, so if
+ * it doesn't finish we won't have RX.
+ *
+ * XXX: Find an interval that's OK for all cards...
+ */
ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
if (ret)
return ret;
- ah->ah_calibration = false;
-
- /* A and G modes can use QAM modulation which requires enabling
- * I and Q calibration. Don't bother in B mode. */
- if (!(mode == AR5K_MODE_11B)) {
- ah->ah_calibration = true;
- AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
- AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
- AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
- AR5K_PHY_IQ_RUN);
- }
-
/*
* Reset queues and start beacon timers at the end of the reset routine
*/
@@ -1154,6 +1192,12 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING);
+
+ data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ;
+ data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ?
+ 0x00000f80 : 0x00001380 ;
+ ath5k_hw_reg_write(ah, data, AR5K_USEC_5211);
+ data = 0;
}
if (ah->ah_version == AR5K_AR5212) {
@@ -1226,7 +1270,7 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
bool set_chip, u16 sleep_duration)
{
unsigned int i;
- u32 staid;
+ u32 staid, data;
ATH5K_TRACE(ah->ah_sc);
staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
@@ -1238,7 +1282,8 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
case AR5K_PM_NETWORK_SLEEP:
if (set_chip)
ath5k_hw_reg_write(ah,
- AR5K_SLEEP_CTL_SLE | sleep_duration,
+ AR5K_SLEEP_CTL_SLE_ALLOW |
+ sleep_duration,
AR5K_SLEEP_CTL);
staid |= AR5K_STA_ID1_PWR_SV;
@@ -1253,13 +1298,24 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
break;
case AR5K_PM_AWAKE:
+
+ staid &= ~AR5K_STA_ID1_PWR_SV;
+
if (!set_chip)
goto commit;
- ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
- AR5K_SLEEP_CTL);
+ /* Preserve sleep duration */
+ data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
+ if( data & 0xffc00000 ){
+ data = 0;
+ } else {
+ data = data & 0xfffcffff;
+ }
- for (i = 5000; i > 0; i--) {
+ ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+ udelay(15);
+
+ for (i = 50; i > 0; i--) {
/* Check if the chip did wake up */
if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
AR5K_PCICFG_SPWR_DN) == 0)
@@ -1267,15 +1323,13 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
/* Wait a bit and retry */
udelay(200);
- ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
- AR5K_SLEEP_CTL);
+ ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
}
/* Fail if the chip didn't wake up */
if (i <= 0)
return -EIO;
- staid &= ~AR5K_STA_ID1_PWR_SV;
break;
default:
@@ -1304,6 +1358,7 @@ void ath5k_hw_start_rx(struct ath5k_hw *ah)
{
ATH5K_TRACE(ah->ah_sc);
ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
+ ath5k_hw_reg_read(ah, AR5K_CR);
}
/*
@@ -1390,6 +1445,7 @@ int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue)
}
/* Start queue */
ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+ ath5k_hw_reg_read(ah, AR5K_CR);
} else {
/* Return if queue is disabled */
if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
@@ -1440,6 +1496,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
/* Stop queue */
ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+ ath5k_hw_reg_read(ah, AR5K_CR);
} else {
/*
* Schedule TX disable and wait until queue is empty
@@ -1456,6 +1513,8 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
/* Clear register */
ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
+ if (pending)
+ return -EBUSY;
}
/* TODO: Check for success else return error */
@@ -1684,6 +1743,7 @@ enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask)
* (they will be re-enabled afterwards).
*/
ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
+ ath5k_hw_reg_read(ah, AR5K_IER);
old_mask = ah->ah_imr;
@@ -1716,6 +1776,7 @@ enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask)
/* ..re-enable interrupts */
ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER);
+ ath5k_hw_reg_read(ah, AR5K_IER);
return old_mask;
}
@@ -3359,11 +3420,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
ath5k_hw_reg_write(ah, ah->ah_turbo ?
AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
- /* Set PHY register 0x9844 (??) */
+ /* Set AR5K_PHY_SETTLING */
ath5k_hw_reg_write(ah, ah->ah_turbo ?
- (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x38 :
- (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x1C,
- AR5K_PHY(17));
+ (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
+ | 0x38 :
+ (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
+ | 0x1C,
+ AR5K_PHY_SETTLING);
/* Set Frame Control Register */
ath5k_hw_reg_write(ah, ah->ah_turbo ?
(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
@@ -3484,7 +3547,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
AR5K_REG_ENABLE_BITS(ah,
AR5K_QUEUE_MISC(queue),
- AR5K_QCU_MISC_TXE);
+ AR5K_QCU_MISC_RDY_VEOL_POLICY);
}
if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c
index 04c84e9da89..2806b21bf90 100644
--- a/drivers/net/wireless/ath5k/initvals.c
+++ b/drivers/net/wireless/ath5k/initvals.c
@@ -489,7 +489,7 @@ static const struct ath5k_ini ar5212_ini[] = {
{ AR5K_QUEUE_TXDP(9), 0x00000000 },
{ AR5K_DCU_FP, 0x00000000 },
{ AR5K_DCU_TXP, 0x00000000 },
- { AR5K_DCU_TX_FILTER, 0x00000000 },
+ { AR5K_DCU_TX_FILTER_0_BASE, 0x00000000 },
/* Unknown table */
{ 0x1078, 0x00000000 },
{ 0x10b8, 0x00000000 },
@@ -679,7 +679,7 @@ static const struct ath5k_ini ar5212_ini[] = {
{ AR5K_PHY(645), 0x00106c10 },
{ AR5K_PHY(646), 0x009c4060 },
{ AR5K_PHY(647), 0x1483800a },
- /* { AR5K_PHY(648), 0x018830c6 },*/ /* 2413 */
+ /* { AR5K_PHY(648), 0x018830c6 },*/ /* 2413/2425 */
{ AR5K_PHY(648), 0x01831061 },
{ AR5K_PHY(649), 0x00000400 },
/*{ AR5K_PHY(650), 0x000001b5 },*/
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c
index afd8689e5c0..fa0d47faf57 100644
--- a/drivers/net/wireless/ath5k/phy.c
+++ b/drivers/net/wireless/ath5k/phy.c
@@ -1020,6 +1020,74 @@ static const struct ath5k_ini_rfgain rfgain_2413[] = {
{ AR5K_RF_GAIN(63), { 0x000000f9 } },
};
+/* Initial RF Gain settings for RF2425 */
+static const struct ath5k_ini_rfgain rfgain_2425[] = {
+ { AR5K_RF_GAIN(0), { 0x00000000 } },
+ { AR5K_RF_GAIN(1), { 0x00000040 } },
+ { AR5K_RF_GAIN(2), { 0x00000080 } },
+ { AR5K_RF_GAIN(3), { 0x00000181 } },
+ { AR5K_RF_GAIN(4), { 0x000001c1 } },
+ { AR5K_RF_GAIN(5), { 0x00000001 } },
+ { AR5K_RF_GAIN(6), { 0x00000041 } },
+ { AR5K_RF_GAIN(7), { 0x00000081 } },
+ { AR5K_RF_GAIN(8), { 0x00000188 } },
+ { AR5K_RF_GAIN(9), { 0x000001c8 } },
+ { AR5K_RF_GAIN(10), { 0x00000008 } },
+ { AR5K_RF_GAIN(11), { 0x00000048 } },
+ { AR5K_RF_GAIN(12), { 0x00000088 } },
+ { AR5K_RF_GAIN(13), { 0x00000189 } },
+ { AR5K_RF_GAIN(14), { 0x000001c9 } },
+ { AR5K_RF_GAIN(15), { 0x00000009 } },
+ { AR5K_RF_GAIN(16), { 0x00000049 } },
+ { AR5K_RF_GAIN(17), { 0x00000089 } },
+ { AR5K_RF_GAIN(18), { 0x000001b0 } },
+ { AR5K_RF_GAIN(19), { 0x000001f0 } },
+ { AR5K_RF_GAIN(20), { 0x00000030 } },
+ { AR5K_RF_GAIN(21), { 0x00000070 } },
+ { AR5K_RF_GAIN(22), { 0x00000171 } },
+ { AR5K_RF_GAIN(23), { 0x000001b1 } },
+ { AR5K_RF_GAIN(24), { 0x000001f1 } },
+ { AR5K_RF_GAIN(25), { 0x00000031 } },
+ { AR5K_RF_GAIN(26), { 0x00000071 } },
+ { AR5K_RF_GAIN(27), { 0x000001b8 } },
+ { AR5K_RF_GAIN(28), { 0x000001f8 } },
+ { AR5K_RF_GAIN(29), { 0x00000038 } },
+ { AR5K_RF_GAIN(30), { 0x00000078 } },
+ { AR5K_RF_GAIN(31), { 0x000000b8 } },
+ { AR5K_RF_GAIN(32), { 0x000001b9 } },
+ { AR5K_RF_GAIN(33), { 0x000001f9 } },
+ { AR5K_RF_GAIN(34), { 0x00000039 } },
+ { AR5K_RF_GAIN(35), { 0x00000079 } },
+ { AR5K_RF_GAIN(36), { 0x000000b9 } },
+ { AR5K_RF_GAIN(37), { 0x000000f9 } },
+ { AR5K_RF_GAIN(38), { 0x000000f9 } },
+ { AR5K_RF_GAIN(39), { 0x000000f9 } },
+ { AR5K_RF_GAIN(40), { 0x000000f9 } },
+ { AR5K_RF_GAIN(41), { 0x000000f9 } },
+ { AR5K_RF_GAIN(42), { 0x000000f9 } },
+ { AR5K_RF_GAIN(43), { 0x000000f9 } },
+ { AR5K_RF_GAIN(44), { 0x000000f9 } },
+ { AR5K_RF_GAIN(45), { 0x000000f9 } },
+ { AR5K_RF_GAIN(46), { 0x000000f9 } },
+ { AR5K_RF_GAIN(47), { 0x000000f9 } },
+ { AR5K_RF_GAIN(48), { 0x000000f9 } },
+ { AR5K_RF_GAIN(49), { 0x000000f9 } },
+ { AR5K_RF_GAIN(50), { 0x000000f9 } },
+ { AR5K_RF_GAIN(51), { 0x000000f9 } },
+ { AR5K_RF_GAIN(52), { 0x000000f9 } },
+ { AR5K_RF_GAIN(53), { 0x000000f9 } },
+ { AR5K_RF_GAIN(54), { 0x000000f9 } },
+ { AR5K_RF_GAIN(55), { 0x000000f9 } },
+ { AR5K_RF_GAIN(56), { 0x000000f9 } },
+ { AR5K_RF_GAIN(57), { 0x000000f9 } },
+ { AR5K_RF_GAIN(58), { 0x000000f9 } },
+ { AR5K_RF_GAIN(59), { 0x000000f9 } },
+ { AR5K_RF_GAIN(60), { 0x000000f9 } },
+ { AR5K_RF_GAIN(61), { 0x000000f9 } },
+ { AR5K_RF_GAIN(62), { 0x000000f9 } },
+ { AR5K_RF_GAIN(63), { 0x000000f9 } },
+};
+
static const struct ath5k_gain_opt rfgain_opt_5112 = {
1,
8,
@@ -1588,8 +1656,8 @@ int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq)
freq = 0; /* only 2Ghz */
break;
case AR5K_RF2425:
- ath5k_rfg = rfgain_2413;
- size = ARRAY_SIZE(rfgain_2413);
+ ath5k_rfg = rfgain_2425;
+ size = ARRAY_SIZE(rfgain_2425);
freq = 0; /* only 2Ghz */
break;
default:
@@ -1830,9 +1898,6 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
data = data0 = data1 = data2 = 0;
c = channel->center_freq;
- /*
- * Set the channel on the RF5112 or newer
- */
if (c < 4800) {
if (!((c - 2224) % 5)) {
data0 = ((2 * (c - 704)) - 3040) / 10;
@@ -1844,7 +1909,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
return -EINVAL;
data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
- } else {
+ } else if ((c - (c % 5)) != 2 || c > 5435) {
if (!(c % 20) && c >= 5120) {
data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
data2 = ath5k_hw_bitswap(3, 2);
@@ -1856,6 +1921,9 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
data2 = ath5k_hw_bitswap(1, 2);
} else
return -EINVAL;
+ } else {
+ data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+ data2 = ath5k_hw_bitswap(0, 2);
}
data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
@@ -1867,6 +1935,45 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
}
/*
+ * Set the channel on the RF2425
+ */
+static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
+ struct ieee80211_channel *channel)
+{
+ u32 data, data0, data2;
+ u16 c;
+
+ data = data0 = data2 = 0;
+ c = channel->center_freq;
+
+ if (c < 4800) {
+ data0 = ath5k_hw_bitswap((c - 2272), 8);
+ data2 = 0;
+ /* ? 5GHz ? */
+ } else if ((c - (c % 5)) != 2 || c > 5435) {
+ if (!(c % 20) && c < 5120)
+ data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
+ else if (!(c % 10))
+ data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
+ else if (!(c % 5))
+ data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
+ else
+ return -EINVAL;
+ data2 = ath5k_hw_bitswap(1, 2);
+ } else {
+ data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+ data2 = ath5k_hw_bitswap(0, 2);
+ }
+
+ data = (data0 << 4) | data2 << 2 | 0x1001;
+
+ ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
+ ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
+
+ return 0;
+}
+
+/*
* Set a channel on the radio chip
*/
int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
@@ -1895,6 +2002,9 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
case AR5K_RF5111:
ret = ath5k_hw_rf5111_channel(ah, channel);
break;
+ case AR5K_RF2425:
+ ret = ath5k_hw_rf2425_channel(ah, channel);
+ break;
default:
ret = ath5k_hw_rf5112_channel(ah, channel);
break;
@@ -1903,6 +2013,15 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
if (ret)
return ret;
+ /* Set JAPAN setting for channel 14 */
+ if (channel->center_freq == 2484) {
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
+ AR5K_PHY_CCKTXCTL_JAPAN);
+ } else {
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
+ AR5K_PHY_CCKTXCTL_WORLD);
+ }
+
ah->ah_current_channel.center_freq = channel->center_freq;
ah->ah_current_channel.hw_value = channel->hw_value;
ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
@@ -1933,6 +2052,8 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
* http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
* &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
*
+ * XXX: Since during noise floor calibration antennas are detached according to
+ * the patent, we should stop tx queues here.
*/
int
ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
@@ -1942,7 +2063,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
s32 noise_floor;
/*
- * Enable noise floor calibration and wait until completion
+ * Enable noise floor calibration
*/
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
AR5K_PHY_AGCCTL_NF);
@@ -1952,7 +2073,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
if (ret) {
ATH5K_ERR(ah->ah_sc,
"noise floor calibration timeout (%uMHz)\n", freq);
- return ret;
+ return -EAGAIN;
}
/* Wait until the noise floor is calibrated and read the value */
@@ -1974,7 +2095,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
ATH5K_ERR(ah->ah_sc,
"noise floor calibration failed (%uMHz)\n", freq);
- return -EIO;
+ return -EAGAIN;
}
ah->ah_noise_floor = noise_floor;
@@ -2087,38 +2208,66 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
}
/*
- * Perform a PHY calibration on RF5111/5112
+ * Perform a PHY calibration on RF5111/5112 and newer chips
*/
static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
struct ieee80211_channel *channel)
{
u32 i_pwr, q_pwr;
s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
+ int i;
ATH5K_TRACE(ah->ah_sc);
if (!ah->ah_calibration ||
- ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
+ ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
goto done;
- ah->ah_calibration = false;
+ /* Calibration has finished, get the results and re-run */
+ for (i = 0; i <= 10; i++) {
+ iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
+ i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
+ q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
+ }
- iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
- i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
- q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
- q_coffd = q_pwr >> 6;
+ q_coffd = q_pwr >> 7;
+ /* No correction */
if (i_coffd == 0 || q_coffd == 0)
goto done;
i_coff = ((-iq_corr) / i_coffd) & 0x3f;
- q_coff = (((s32)i_pwr / q_coffd) - 64) & 0x1f;
- /* Commit new IQ value */
+ /* Boundary check */
+ if (i_coff > 31)
+ i_coff = 31;
+ if (i_coff < -32)
+ i_coff = -32;
+
+ q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f;
+
+ /* Boundary check */
+ if (q_coff > 15)
+ q_coff = 15;
+ if (q_coff < -16)
+ q_coff = -16;
+
+ /* Commit new I/Q value */
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
+ /* Re-enable calibration -if we don't we'll commit
+ * the same values again and again */
+ AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+ AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN);
+
done:
+
+ /* TODO: Separate noise floor calibration from I/Q calibration
+ * since noise floor calibration interrupts rx path while I/Q
+ * calibration doesn't. We don't need to run noise floor calibration
+ * as often as I/Q calibration.*/
ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
/* Request RF gain */
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h
index 30629b3e37c..7562bf173d3 100644
--- a/drivers/net/wireless/ath5k/reg.h
+++ b/drivers/net/wireless/ath5k/reg.h
@@ -53,7 +53,7 @@
#define AR5K_CR_TXD0 0x00000008 /* TX Disable for queue 0 on 5210 */
#define AR5K_CR_TXD1 0x00000010 /* TX Disable for queue 1 on 5210 */
#define AR5K_CR_RXD 0x00000020 /* RX Disable */
-#define AR5K_CR_SWI 0x00000040
+#define AR5K_CR_SWI 0x00000040 /* Software Interrupt */
/*
* RX Descriptor Pointer register
@@ -65,19 +65,19 @@
*/
#define AR5K_CFG 0x0014 /* Register Address */
#define AR5K_CFG_SWTD 0x00000001 /* Byte-swap TX descriptor (for big endian archs) */
-#define AR5K_CFG_SWTB 0x00000002 /* Byte-swap TX buffer (?) */
+#define AR5K_CFG_SWTB 0x00000002 /* Byte-swap TX buffer */
#define AR5K_CFG_SWRD 0x00000004 /* Byte-swap RX descriptor */
-#define AR5K_CFG_SWRB 0x00000008 /* Byte-swap RX buffer (?) */
-#define AR5K_CFG_SWRG 0x00000010 /* Byte-swap Register values (?) */
-#define AR5K_CFG_ADHOC 0x00000020 /* [5211+] */
+#define AR5K_CFG_SWRB 0x00000008 /* Byte-swap RX buffer */
+#define AR5K_CFG_SWRG 0x00000010 /* Byte-swap Register access */
+#define AR5K_CFG_ADHOC 0x00000020 /* AP/Adhoc indication [5211+] */
#define AR5K_CFG_PHY_OK 0x00000100 /* [5211+] */
#define AR5K_CFG_EEBS 0x00000200 /* EEPROM is busy */
-#define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (?) */
+#define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (Disable dynamic clock) */
#define AR5K_CFG_TXCNT 0x00007800 /* Tx frame count (?) [5210] */
#define AR5K_CFG_TXCNT_S 11
#define AR5K_CFG_TXFSTAT 0x00008000 /* Tx frame status (?) [5210] */
#define AR5K_CFG_TXFSTRT 0x00010000 /* [5210] */
-#define AR5K_CFG_PCI_THRES 0x00060000 /* [5211+] */
+#define AR5K_CFG_PCI_THRES 0x00060000 /* PCI Master req q threshold [5211+] */
#define AR5K_CFG_PCI_THRES_S 17
/*
@@ -162,35 +162,40 @@
/*
* Transmit configuration register
*/
-#define AR5K_TXCFG 0x0030 /* Register Address */
-#define AR5K_TXCFG_SDMAMR 0x00000007 /* DMA size */
-#define AR5K_TXCFG_SDMAMR_S 0
-#define AR5K_TXCFG_B_MODE 0x00000008 /* Set b mode for 5111 (enable 2111) */
-#define AR5K_TXCFG_TXFSTP 0x00000008 /* TX DMA full Stop [5210] */
-#define AR5K_TXCFG_TXFULL 0x000003f0 /* TX Triger level mask */
-#define AR5K_TXCFG_TXFULL_S 4
-#define AR5K_TXCFG_TXFULL_0B 0x00000000
-#define AR5K_TXCFG_TXFULL_64B 0x00000010
-#define AR5K_TXCFG_TXFULL_128B 0x00000020
-#define AR5K_TXCFG_TXFULL_192B 0x00000030
-#define AR5K_TXCFG_TXFULL_256B 0x00000040
-#define AR5K_TXCFG_TXCONT_EN 0x00000080
-#define AR5K_TXCFG_DMASIZE 0x00000100 /* Flag for passing DMA size [5210] */
-#define AR5K_TXCFG_JUMBO_TXE 0x00000400 /* Enable jumbo frames transmition (?) [5211+] */
-#define AR5K_TXCFG_RTSRND 0x00001000 /* [5211+] */
-#define AR5K_TXCFG_FRMPAD_DIS 0x00002000 /* [5211+] */
-#define AR5K_TXCFG_RDY_DIS 0x00004000 /* [5211+] */
+#define AR5K_TXCFG 0x0030 /* Register Address */
+#define AR5K_TXCFG_SDMAMR 0x00000007 /* DMA size (read) */
+#define AR5K_TXCFG_SDMAMR_S 0
+#define AR5K_TXCFG_B_MODE 0x00000008 /* Set b mode for 5111 (enable 2111) */
+#define AR5K_TXCFG_TXFSTP 0x00000008 /* TX DMA full Stop [5210] */
+#define AR5K_TXCFG_TXFULL 0x000003f0 /* TX Triger level mask */
+#define AR5K_TXCFG_TXFULL_S 4
+#define AR5K_TXCFG_TXFULL_0B 0x00000000
+#define AR5K_TXCFG_TXFULL_64B 0x00000010
+#define AR5K_TXCFG_TXFULL_128B 0x00000020
+#define AR5K_TXCFG_TXFULL_192B 0x00000030
+#define AR5K_TXCFG_TXFULL_256B 0x00000040
+#define AR5K_TXCFG_TXCONT_EN 0x00000080
+#define AR5K_TXCFG_DMASIZE 0x00000100 /* Flag for passing DMA size [5210] */
+#define AR5K_TXCFG_JUMBO_DESC_EN 0x00000400 /* Enable jumbo tx descriptors [5211+] */
+#define AR5K_TXCFG_ADHOC_BCN_ATIM 0x00000800 /* Adhoc Beacon ATIM Policy */
+#define AR5K_TXCFG_ATIM_WINDOW_DEF_DIS 0x00001000 /* Disable ATIM window defer [5211+] */
+#define AR5K_TXCFG_RTSRND 0x00001000 /* [5211+] */
+#define AR5K_TXCFG_FRMPAD_DIS 0x00002000 /* [5211+] */
+#define AR5K_TXCFG_RDY_CBR_DIS 0x00004000 /* Ready time CBR disable [5211+] */
+#define AR5K_TXCFG_JUMBO_FRM_MODE 0x00008000 /* Jumbo frame mode [5211+] */
+#define AR5K_TXCFG_DCU_CACHING_DIS 0x00010000 /* Disable DCU caching */
/*
* Receive configuration register
*/
#define AR5K_RXCFG 0x0034 /* Register Address */
-#define AR5K_RXCFG_SDMAMW 0x00000007 /* DMA size */
+#define AR5K_RXCFG_SDMAMW 0x00000007 /* DMA size (write) */
#define AR5K_RXCFG_SDMAMW_S 0
-#define AR5K_RXCFG_DEF_ANTENNA 0x00000008 /* Default antenna */
-#define AR5K_RXCFG_ZLFDMA 0x00000010 /* Zero-length DMA */
-#define AR5K_RXCFG_JUMBO_RXE 0x00000020 /* Enable jumbo frames reception (?) [5211+] */
-#define AR5K_RXCFG_JUMBO_WRAP 0x00000040 /* Wrap jumbo frames (?) [5211+] */
+#define AR5K_RXCFG_ZLFDMA 0x00000008 /* Enable Zero-length frame DMA */
+#define AR5K_RXCFG_DEF_ANTENNA 0x00000010 /* Default antenna (?) */
+#define AR5K_RXCFG_JUMBO_RXE 0x00000020 /* Enable jumbo rx descriptors [5211+] */
+#define AR5K_RXCFG_JUMBO_WRAP 0x00000040 /* Wrap jumbo frames [5211+] */
+#define AR5K_RXCFG_SLE_ENTRY 0x00000080 /* Sleep entry policy */
/*
* Receive jumbo descriptor last address register
@@ -202,35 +207,35 @@
* MIB control register
*/
#define AR5K_MIBC 0x0040 /* Register Address */
-#define AR5K_MIBC_COW 0x00000001
-#define AR5K_MIBC_FMC 0x00000002 /* Freeze Mib Counters (?) */
-#define AR5K_MIBC_CMC 0x00000004 /* Clean Mib Counters (?) */
-#define AR5K_MIBC_MCS 0x00000008
+#define AR5K_MIBC_COW 0x00000001 /* Warn test indicator */
+#define AR5K_MIBC_FMC 0x00000002 /* Freeze MIB Counters */
+#define AR5K_MIBC_CMC 0x00000004 /* Clean MIB Counters */
+#define AR5K_MIBC_MCS 0x00000008 /* MIB counter strobe */
/*
* Timeout prescale register
*/
#define AR5K_TOPS 0x0044
-#define AR5K_TOPS_M 0x0000ffff /* [5211+] (?) */
+#define AR5K_TOPS_M 0x0000ffff
/*
* Receive timeout register (no frame received)
*/
#define AR5K_RXNOFRM 0x0048
-#define AR5K_RXNOFRM_M 0x000003ff /* [5211+] (?) */
+#define AR5K_RXNOFRM_M 0x000003ff
/*
* Transmit timeout register (no frame sent)
*/
#define AR5K_TXNOFRM 0x004c
-#define AR5K_TXNOFRM_M 0x000003ff /* [5211+] (?) */
-#define AR5K_TXNOFRM_QCU 0x000ffc00 /* [5211+] (?) */
+#define AR5K_TXNOFRM_M 0x000003ff
+#define AR5K_TXNOFRM_QCU 0x000ffc00
/*
* Receive frame gap timeout register
*/
#define AR5K_RPGTO 0x0050
-#define AR5K_RPGTO_M 0x000003ff /* [5211+] (?) */
+#define AR5K_RPGTO_M 0x000003ff
/*
* Receive frame count limit register
@@ -241,6 +246,7 @@
/*
* Misc settings register
+ * (reserved0-3)
*/
#define AR5K_MISC 0x0058 /* Register Address */
#define AR5K_MISC_DMA_OBS_M 0x000001e0
@@ -256,6 +262,7 @@
/*
* QCU/DCU clock gating register (5311)
+ * (reserved4-5)
*/
#define AR5K_QCUDCU_CLKGT 0x005c /* Register Address (?) */
#define AR5K_QCUDCU_CLKGT_QCU 0x0000ffff /* Mask for QCU clock */
@@ -284,18 +291,18 @@
#define AR5K_ISR_TXEOL 0x00000400 /* Empty TX descriptor */
#define AR5K_ISR_TXURN 0x00000800 /* Transmit FIFO underrun */
#define AR5K_ISR_MIB 0x00001000 /* Update MIB counters */
-#define AR5K_ISR_SWI 0x00002000 /* Software interrupt (?) */
+#define AR5K_ISR_SWI 0x00002000 /* Software interrupt */
#define AR5K_ISR_RXPHY 0x00004000 /* PHY error */
-#define AR5K_ISR_RXKCM 0x00008000
+#define AR5K_ISR_RXKCM 0x00008000 /* RX Key cache miss */
#define AR5K_ISR_SWBA 0x00010000 /* Software beacon alert */
#define AR5K_ISR_BRSSI 0x00020000
#define AR5K_ISR_BMISS 0x00040000 /* Beacon missed */
#define AR5K_ISR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */
#define AR5K_ISR_BNR 0x00100000 /* Beacon not ready [5211+] */
-#define AR5K_ISR_MCABT 0x00100000 /* [5210] */
-#define AR5K_ISR_RXCHIRP 0x00200000 /* [5212+] */
-#define AR5K_ISR_SSERR 0x00200000 /* [5210] */
-#define AR5K_ISR_DPERR 0x00400000 /* [5210] */
+#define AR5K_ISR_MCABT 0x00100000 /* Master Cycle Abort [5210] */
+#define AR5K_ISR_RXCHIRP 0x00200000 /* CHIRP Received [5212+] */
+#define AR5K_ISR_SSERR 0x00200000 /* Signaled System Error [5210] */
+#define AR5K_ISR_DPERR 0x00400000 /* Det par Error (?) [5210] */
#define AR5K_ISR_TIM 0x00800000 /* [5210] */
#define AR5K_ISR_BCNMISC 0x00800000 /* [5212+] */
#define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill)*/
@@ -320,14 +327,14 @@
#define AR5K_SISR2 0x008c /* Register Address [5211+] */
#define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
-#define AR5K_SISR2_MCABT 0x00100000
-#define AR5K_SISR2_SSERR 0x00200000
-#define AR5K_SISR2_DPERR 0x00400000
+#define AR5K_SISR2_MCABT 0x00100000 /* Master Cycle Abort */
+#define AR5K_SISR2_SSERR 0x00200000 /* Signaled System Error */
+#define AR5K_SISR2_DPERR 0x00400000 /* Det par Error (?) */
#define AR5K_SISR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */
-#define AR5K_SISR2_DTIM_SYNC 0x04000000 /* [5212+] */
-#define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* [5212+] */
-#define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* [5212+] */
+#define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */
+#define AR5K_SISR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */
+#define AR5K_SISR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */
#define AR5K_SISR2_DTIM 0x20000000 /* [5212+] */
#define AR5K_SISR3 0x0090 /* Register Address [5211+] */
@@ -368,18 +375,18 @@
#define AR5K_IMR_TXEOL 0x00000400 /* Empty TX descriptor*/
#define AR5K_IMR_TXURN 0x00000800 /* Transmit FIFO underrun*/
#define AR5K_IMR_MIB 0x00001000 /* Update MIB counters*/
-#define AR5K_IMR_SWI 0x00002000
+#define AR5K_IMR_SWI 0x00002000 /* Software interrupt */
#define AR5K_IMR_RXPHY 0x00004000 /* PHY error*/
-#define AR5K_IMR_RXKCM 0x00008000
+#define AR5K_IMR_RXKCM 0x00008000 /* RX Key cache miss */
#define AR5K_IMR_SWBA 0x00010000 /* Software beacon alert*/
#define AR5K_IMR_BRSSI 0x00020000
#define AR5K_IMR_BMISS 0x00040000 /* Beacon missed*/
#define AR5K_IMR_HIUERR 0x00080000 /* Host Interface Unit error [5211+] */
#define AR5K_IMR_BNR 0x00100000 /* Beacon not ready [5211+] */
-#define AR5K_IMR_MCABT 0x00100000 /* [5210] */
-#define AR5K_IMR_RXCHIRP 0x00200000 /* [5212+]*/
-#define AR5K_IMR_SSERR 0x00200000 /* [5210] */
-#define AR5K_IMR_DPERR 0x00400000 /* [5210] */
+#define AR5K_IMR_MCABT 0x00100000 /* Master Cycle Abort [5210] */
+#define AR5K_IMR_RXCHIRP 0x00200000 /* CHIRP Received [5212+]*/
+#define AR5K_IMR_SSERR 0x00200000 /* Signaled System Error [5210] */
+#define AR5K_IMR_DPERR 0x00400000 /* Det par Error (?) [5210] */
#define AR5K_IMR_TIM 0x00800000 /* [5211+] */
#define AR5K_IMR_BCNMISC 0x00800000 /* [5212+] */
#define AR5K_IMR_GPIO 0x01000000 /* GPIO (rf kill)*/
@@ -405,14 +412,14 @@
#define AR5K_SIMR2 0x00ac /* Register Address [5211+] */
#define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
#define AR5K_SIMR2_QCU_TXURN_S 0
-#define AR5K_SIMR2_MCABT 0x00100000
-#define AR5K_SIMR2_SSERR 0x00200000
-#define AR5K_SIMR2_DPERR 0x00400000
+#define AR5K_SIMR2_MCABT 0x00100000 /* Master Cycle Abort */
+#define AR5K_SIMR2_SSERR 0x00200000 /* Signaled System Error */
+#define AR5K_SIMR2_DPERR 0x00400000 /* Det par Error (?) */
#define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */
-#define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* [5212+] */
-#define AR5K_SIMR2_BCN_TIMEOUT 0x08000000 /* [5212+] */
-#define AR5K_SIMR2_CAB_TIMEOUT 0x10000000 /* [5212+] */
+#define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */
+#define AR5K_SIMR2_BCN_TIMEOUT 0x08000000 /* Beacon Timeout [5212+] */
+#define AR5K_SIMR2_CAB_TIMEOUT 0x10000000 /* CAB Timeout [5212+] */
#define AR5K_SIMR2_DTIM 0x20000000 /* [5212+] */
#define AR5K_SIMR3 0x00b0 /* Register Address [5211+] */
@@ -425,23 +432,69 @@
#define AR5K_SIMR4_QTRIG 0x000003ff /* Mask for QTRIG */
#define AR5K_SIMR4_QTRIG_S 0
+/*
+ * DMA Debug registers 0-7
+ * 0xe0 - 0xfc
+ */
/*
* Decompression mask registers [5212+]
*/
-#define AR5K_DCM_ADDR 0x0400 /*Decompression mask address (?)*/
-#define AR5K_DCM_DATA 0x0404 /*Decompression mask data (?)*/
+#define AR5K_DCM_ADDR 0x0400 /*Decompression mask address (index) */
+#define AR5K_DCM_DATA 0x0404 /*Decompression mask data */
+
+/*
+ * Wake On Wireless pattern control register [5212+]
+ */
+#define AR5K_WOW_PCFG 0x0410 /* Register Address */
+#define AR5K_WOW_PCFG_PAT_MATCH_EN 0x00000001 /* Pattern match enable */
+#define AR5K_WOW_PCFG_LONG_FRAME_POL 0x00000002 /* Long frame policy */
+#define AR5K_WOW_PCFG_WOBMISS 0x00000004 /* Wake on bea(con) miss (?) */
+#define AR5K_WOW_PCFG_PAT_0_EN 0x00000100 /* Enable pattern 0 */
+#define AR5K_WOW_PCFG_PAT_1_EN 0x00000200 /* Enable pattern 1 */
+#define AR5K_WOW_PCFG_PAT_2_EN 0x00000400 /* Enable pattern 2 */
+#define AR5K_WOW_PCFG_PAT_3_EN 0x00000800 /* Enable pattern 3 */
+#define AR5K_WOW_PCFG_PAT_4_EN 0x00001000 /* Enable pattern 4 */
+#define AR5K_WOW_PCFG_PAT_5_EN 0x00002000 /* Enable pattern 5 */
+
+/*
+ * Wake On Wireless pattern index register (?) [5212+]
+ */
+#define AR5K_WOW_PAT_IDX 0x0414
+
+/*
+ * Wake On Wireless pattern data register [5212+]
+ */
+#define AR5K_WOW_PAT_DATA 0x0418 /* Register Address */
+#define AR5K_WOW_PAT_DATA_0_3_V 0x00000001 /* Pattern 0, 3 value */
+#define AR5K_WOW_PAT_DATA_1_4_V 0x00000100 /* Pattern 1, 4 value */
+#define AR5K_WOW_PAT_DATA_2_5_V 0x00010000 /* Pattern 2, 5 value */
+#define AR5K_WOW_PAT_DATA_0_3_M 0x01000000 /* Pattern 0, 3 mask */
+#define AR5K_WOW_PAT_DATA_1_4_M 0x04000000 /* Pattern 1, 4 mask */
+#define AR5K_WOW_PAT_DATA_2_5_M 0x10000000 /* Pattern 2, 5 mask */
/*
* Decompression configuration registers [5212+]
*/
-#define AR5K_DCCFG 0x0420
+#define AR5K_DCCFG 0x0420 /* Register Address */
+#define AR5K_DCCFG_GLOBAL_EN 0x00000001 /* Enable decompression on all queues */
+#define AR5K_DCCFG_BYPASS_EN 0x00000002 /* Bypass decompression */
+#define AR5K_DCCFG_BCAST_EN 0x00000004 /* Enable decompression for bcast frames */
+#define AR5K_DCCFG_MCAST_EN 0x00000008 /* Enable decompression for mcast frames */
/*
* Compression configuration registers [5212+]
*/
-#define AR5K_CCFG 0x0600
-#define AR5K_CCFG_CUP 0x0604
+#define AR5K_CCFG 0x0600 /* Register Address */
+#define AR5K_CCFG_WINDOW_SIZE 0x00000007 /* Compression window size */
+#define AR5K_CCFG_CPC_EN 0x00000008 /* Enable performance counters */
+
+#define AR5K_CCFG_CCU 0x0604 /* Register Address */
+#define AR5K_CCFG_CCU_CUP_EN 0x00000001 /* CCU Catchup enable */
+#define AR5K_CCFG_CCU_CREDIT 0x00000002 /* CCU Credit (field) */
+#define AR5K_CCFG_CCU_CD_THRES 0x00000080 /* CCU Cyc(lic?) debt threshold (field) */
+#define AR5K_CCFG_CCU_CUP_LCNT 0x00010000 /* CCU Catchup lit(?) count */
+#define AR5K_CCFG_CCU_INIT 0x00100200 /* Initial value during reset */
/*
* Compression performance counter registers [5212+]
@@ -450,7 +503,7 @@
#define AR5K_CPC1 0x0614 /* Compression performance counter 1*/
#define AR5K_CPC2 0x0618 /* Compression performance counter 2 */
#define AR5K_CPC3 0x061c /* Compression performance counter 3 */
-#define AR5K_CPCORN 0x0620 /* Compression performance overrun (?) */
+#define AR5K_CPCOVF 0x0620 /* Compression performance overflow */
/*
@@ -466,8 +519,6 @@
* set/clear, which contain status for all queues (we shift by 1 for each
* queue). To access these registers easily we define some macros here
* that are used inside HAL. For more infos check out *_tx_queue functs.
- *
- * TODO: Boundary checking on macros (here?)
*/
/*
@@ -513,7 +564,6 @@
#define AR5K_QCU_RDYTIMECFG_BASE 0x0900 /* Register Address - Queue0 RDYTIMECFG */
#define AR5K_QCU_RDYTIMECFG_INTVAL 0x00ffffff /* Ready time interval mask */
#define AR5K_QCU_RDYTIMECFG_INTVAL_S 0
-#define AR5K_QCU_RDYTIMECFG_DURATION 0x00ffffff /* Ready time duration mask */
#define AR5K_QCU_RDYTIMECFG_ENABLE 0x01000000 /* Ready time enable mask */
#define AR5K_QUEUE_RDYTIMECFG(_q) AR5K_QUEUE_REG(AR5K_QCU_RDYTIMECFG_BASE, _q)
@@ -534,19 +584,20 @@
*/
#define AR5K_QCU_MISC_BASE 0x09c0 /* Register Address -Queue0 MISC */
#define AR5K_QCU_MISC_FRSHED_M 0x0000000f /* Frame sheduling mask */
-#define AR5K_QCU_MISC_FRSHED_ASAP 0 /* ASAP */
-#define AR5K_QCU_MISC_FRSHED_CBR 1 /* Constant Bit Rate */
-#define AR5K_QCU_MISC_FRSHED_DBA_GT 2 /* DMA Beacon alert gated (?) */
-#define AR5K_QCU_MISC_FRSHED_TIM_GT 3 /* Time gated (?) */
+#define AR5K_QCU_MISC_FRSHED_ASAP 0 /* ASAP */
+#define AR5K_QCU_MISC_FRSHED_CBR 1 /* Constant Bit Rate */
+#define AR5K_QCU_MISC_FRSHED_DBA_GT 2 /* DMA Beacon alert gated (?) */
+#define AR5K_QCU_MISC_FRSHED_TIM_GT 3 /* Time gated (?) */
#define AR5K_QCU_MISC_FRSHED_BCN_SENT_GT 4 /* Beacon sent gated (?) */
#define AR5K_QCU_MISC_ONESHOT_ENABLE 0x00000010 /* Oneshot enable */
#define AR5K_QCU_MISC_CBREXP 0x00000020 /* CBR expired (normal queue) */
#define AR5K_QCU_MISC_CBREXP_BCN 0x00000040 /* CBR expired (beacon queue) */
-#define AR5K_QCU_MISC_BCN_ENABLE 0x00000080 /* Beacons enabled */
-#define AR5K_QCU_MISC_CBR_THRES_ENABLE 0x00000100 /* CBR threshold enabled (?) */
-#define AR5K_QCU_MISC_TXE 0x00000200 /* TXE reset when RDYTIME enalbed (?) */
-#define AR5K_QCU_MISC_CBR 0x00000400 /* CBR threshold reset (?) */
-#define AR5K_QCU_MISC_DCU_EARLY 0x00000800 /* DCU reset (?) */
+#define AR5K_QCU_MISC_BCN_ENABLE 0x00000080 /* Enable Beacon use */
+#define AR5K_QCU_MISC_CBR_THRES_ENABLE 0x00000100 /* CBR threshold enabled */
+#define AR5K_QCU_MISC_RDY_VEOL_POLICY 0x00000200 /* TXE reset when RDYTIME enalbed */
+#define AR5K_QCU_MISC_CBR_RESET_CNT 0x00000400 /* CBR threshold (counter) reset */
+#define AR5K_QCU_MISC_DCU_EARLY 0x00000800 /* DCU early termination */
+#define AR5K_QCU_MISC_DCU_CMP_EN 0x00001000 /* Enable frame compression */
#define AR5K_QUEUE_MISC(_q) AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q)
@@ -555,7 +606,7 @@
*/
#define AR5K_QCU_STS_BASE 0x0a00 /* Register Address - Queue0 STS */
#define AR5K_QCU_STS_FRMPENDCNT 0x00000003 /* Frames pending counter */
-#define AR5K_QCU_STS_CBREXPCNT 0x0000ff00 /* CBR expired counter (?) */
+#define AR5K_QCU_STS_CBREXPCNT 0x0000ff00 /* CBR expired counter */
#define AR5K_QUEUE_STATUS(_q) AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q)
/*
@@ -569,9 +620,11 @@
*/
#define AR5K_QCU_CBB_SELECT 0x0b00
#define AR5K_QCU_CBB_ADDR 0x0b04
+#define AR5K_QCU_CBB_ADDR_S 9
/*
* QCU compression buffer configuration register [5212+]
+ * (buffer size)
*/
#define AR5K_QCU_CBCFG 0x0b08
@@ -652,80 +705,100 @@
* No lockout means there is no special handling.
*/
#define AR5K_DCU_MISC_BASE 0x1100 /* Register Address -Queue0 DCU_MISC */
-#define AR5K_DCU_MISC_BACKOFF 0x000007ff /* Mask for backoff setting (?) */
+#define AR5K_DCU_MISC_BACKOFF 0x000007ff /* Mask for backoff threshold */
#define AR5K_DCU_MISC_BACKOFF_FRAG 0x00000200 /* Enable backoff while bursting */
-#define AR5K_DCU_MISC_HCFPOLL_ENABLE 0x00000800 /* CF - Poll (?) */
-#define AR5K_DCU_MISC_BACKOFF_PERSIST 0x00001000 /* Persistent backoff (?) */
-#define AR5K_DCU_MISC_FRMPRFTCH_ENABLE 0x00002000 /* Enable frame pre-fetch (?) */
+#define AR5K_DCU_MISC_HCFPOLL_ENABLE 0x00000800 /* CF - Poll enable */
+#define AR5K_DCU_MISC_BACKOFF_PERSIST 0x00001000 /* Persistent backoff */
+#define AR5K_DCU_MISC_FRMPRFTCH_ENABLE 0x00002000 /* Enable frame pre-fetch */
#define AR5K_DCU_MISC_VIRTCOL 0x0000c000 /* Mask for Virtual Collision (?) */
-#define AR5K_DCU_MISC_VIRTCOL_NORMAL 0
-#define AR5K_DCU_MISC_VIRTCOL_MODIFIED 1
-#define AR5K_DCU_MISC_VIRTCOL_IGNORE 2
-#define AR5K_DCU_MISC_BCN_ENABLE 0x00010000 /* Beacon enable (?) */
+#define AR5K_DCU_MISC_VIRTCOL_NORMAL 0
+#define AR5K_DCU_MISC_VIRTCOL_MODIFIED 1
+#define AR5K_DCU_MISC_VIRTCOL_IGNORE 2
+#define AR5K_DCU_MISC_BCN_ENABLE 0x00010000 /* Enable Beacon use */
#define AR5K_DCU_MISC_ARBLOCK_CTL 0x00060000 /* Arbiter lockout control mask */
#define AR5K_DCU_MISC_ARBLOCK_CTL_S 17
-#define AR5K_DCU_MISC_ARBLOCK_CTL_NONE 0 /* No arbiter lockout */
+#define AR5K_DCU_MISC_ARBLOCK_CTL_NONE 0 /* No arbiter lockout */
#define AR5K_DCU_MISC_ARBLOCK_CTL_INTFRM 1 /* Intra-frame lockout */
#define AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL 2 /* Global lockout */
-#define AR5K_DCU_MISC_ARBLOCK_IGNORE 0x00080000
-#define AR5K_DCU_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Disable sequence number increment (?) */
-#define AR5K_DCU_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Disable post-frame backoff (?) */
-#define AR5K_DCU_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual Collision policy (?) */
-#define AR5K_DCU_MISC_BLOWN_IFS_POLICY 0x00800000
+#define AR5K_DCU_MISC_ARBLOCK_IGNORE 0x00080000 /* Ignore Arbiter lockout */
+#define AR5K_DCU_MISC_SEQ_NUM_INCR_DIS 0x00100000 /* Disable sequence number increment */
+#define AR5K_DCU_MISC_POST_FR_BKOFF_DIS 0x00200000 /* Disable post-frame backoff */
+#define AR5K_DCU_MISC_VIRT_COLL_POLICY 0x00400000 /* Virtual Collision cw policy */
+#define AR5K_DCU_MISC_BLOWN_IFS_POLICY 0x00800000 /* Blown IFS policy (?) */
#define AR5K_DCU_MISC_SEQNUM_CTL 0x01000000 /* Sequence number control (?) */
#define AR5K_QUEUE_DFS_MISC(_q) AR5K_QUEUE_REG(AR5K_DCU_MISC_BASE, _q)
/*
* DCU frame sequence number registers
*/
-#define AR5K_DCU_SEQNUM_BASE 0x1140
-#define AR5K_DCU_SEQNUM_M 0x00000fff
+#define AR5K_DCU_SEQNUM_BASE 0x1140
+#define AR5K_DCU_SEQNUM_M 0x00000fff
#define AR5K_QUEUE_DFS_SEQNUM(_q) AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q)
/*
- * DCU global IFS SIFS registers
+ * DCU global IFS SIFS register
*/
#define AR5K_DCU_GBL_IFS_SIFS 0x1030
#define AR5K_DCU_GBL_IFS_SIFS_M 0x0000ffff
/*
- * DCU global IFS slot interval registers
+ * DCU global IFS slot interval register
*/
#define AR5K_DCU_GBL_IFS_SLOT 0x1070
#define AR5K_DCU_GBL_IFS_SLOT_M 0x0000ffff
/*
- * DCU global IFS EIFS registers
+ * DCU global IFS EIFS register
*/
#define AR5K_DCU_GBL_IFS_EIFS 0x10b0
#define AR5K_DCU_GBL_IFS_EIFS_M 0x0000ffff
/*
- * DCU global IFS misc registers
+ * DCU global IFS misc register
+ *
+ * LFSR stands for Linear Feedback Shift Register
+ * and it's used for generating pseudo-random
+ * number sequences.
+ *
+ * (If i understand corectly, random numbers are
+ * used for idle sensing -multiplied with cwmin/max etc-)
*/
#define AR5K_DCU_GBL_IFS_MISC 0x10f0 /* Register Address */
-#define AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE 0x00000007
-#define AR5K_DCU_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode (?) */
-#define AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC 0x000003f0 /* SIFS Duration mask (?) */
-#define AR5K_DCU_GBL_IFS_MISC_USEC_DUR 0x000ffc00
-#define AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY 0x00300000
+#define AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE 0x00000007 /* LFSR Slice Select */
+#define AR5K_DCU_GBL_IFS_MISC_TURBO_MODE 0x00000008 /* Turbo mode */
+#define AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC 0x000003f0 /* SIFS Duration mask */
+#define AR5K_DCU_GBL_IFS_MISC_USEC_DUR 0x000ffc00 /* USEC Duration mask */
+#define AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY 0x00300000 /* DCU Arbiter delay mask */
+#define AR5K_DCU_GBL_IFS_MISC_SIFS_CNT_RST 0x00400000 /* SIFC cnt reset policy (?) */
+#define AR5K_DCU_GBL_IFS_MISC_AIFS_CNT_RST 0x00800000 /* AIFS cnt reset policy (?) */
+#define AR5K_DCU_GBL_IFS_MISC_RND_LFSR_SL_DIS 0x01000000 /* Disable random LFSR slice */
/*
* DCU frame prefetch control register
*/
-#define AR5K_DCU_FP 0x1230
+#define AR5K_DCU_FP 0x1230 /* Register Address */
+#define AR5K_DCU_FP_NOBURST_DCU_EN 0x00000001 /* Enable non-burst prefetch on DCU (?) */
+#define AR5K_DCU_FP_NOBURST_EN 0x00000010 /* Enable non-burst prefetch (?) */
+#define AR5K_DCU_FP_BURST_DCU_EN 0x00000020 /* Enable burst prefetch on DCU (?) */
/*
* DCU transmit pause control/status register
*/
#define AR5K_DCU_TXP 0x1270 /* Register Address */
-#define AR5K_DCU_TXP_M 0x000003ff /* Tx pause mask (?) */
-#define AR5K_DCU_TXP_STATUS 0x00010000 /* Tx pause status (?) */
+#define AR5K_DCU_TXP_M 0x000003ff /* Tx pause mask */
+#define AR5K_DCU_TXP_STATUS 0x00010000 /* Tx pause status */
+
+/*
+ * DCU transmit filter table 0 (32 entries)
+ */
+#define AR5K_DCU_TX_FILTER_0_BASE 0x1038
+#define AR5K_DCU_TX_FILTER_0(_n) (AR5K_DCU_TX_FILTER_0_BASE + (_n * 64))
/*
- * DCU transmit filter register
+ * DCU transmit filter table 1 (16 entries)
*/
-#define AR5K_DCU_TX_FILTER 0x1038
+#define AR5K_DCU_TX_FILTER_1_BASE 0x103c
+#define AR5K_DCU_TX_FILTER_1(_n) (AR5K_DCU_TX_FILTER_1_BASE + ((_n - 32) * 64))
/*
* DCU clear transmit filter register
@@ -739,9 +812,6 @@
/*
* Reset control register
- *
- * 4 and 8 are not used in 5211/5212 and
- * 2 means "baseband reset" on 5211/5212.
*/
#define AR5K_RESET_CTL 0x4000 /* Register Address */
#define AR5K_RESET_CTL_PCU 0x00000001 /* Protocol Control Unit reset */
@@ -765,6 +835,7 @@
#define AR5K_SLEEP_CTL_SLE_SLP 0x00010000 /* Force chip sleep */
#define AR5K_SLEEP_CTL_SLE_ALLOW 0x00020000
#define AR5K_SLEEP_CTL_SLE_UNITS 0x00000008 /* [5211+] */
+/* more bits */
/*
* Interrupt pending register
@@ -776,13 +847,14 @@
* Sleep force register
*/
#define AR5K_SFR 0x400c
-#define AR5K_SFR_M 0x00000001
+#define AR5K_SFR_EN 0x00000001
/*
* PCI configuration register
*/
#define AR5K_PCICFG 0x4010 /* Register Address */
#define AR5K_PCICFG_EEAE 0x00000001 /* Eeprom access enable [5210] */
+#define AR5K_PCICFG_SLEEP_CLOCK_EN 0x00000002 /* Enable sleep clock (?) */
#define AR5K_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable [5211+] */
#define AR5K_PCICFG_EESIZE 0x00000018 /* Mask for EEPROM size [5211+] */
#define AR5K_PCICFG_EESIZE_S 3
@@ -798,19 +870,21 @@
#define AR5K_PCICFG_CBEFIX_DIS 0x00000400 /* Disable CBE fix (?) */
#define AR5K_PCICFG_SL_INTEN 0x00000800 /* Enable interrupts when asleep (?) */
#define AR5K_PCICFG_LED_BCTL 0x00001000 /* Led blink (?) [5210] */
-#define AR5K_PCICFG_SL_INPEN 0x00002800 /* Sleep even whith pending interrupts (?) */
+#define AR5K_PCICFG_UNK 0x00001000 /* Passed on some parts durring attach (?) */
+#define AR5K_PCICFG_SL_INPEN 0x00002000 /* Sleep even whith pending interrupts (?) */
#define AR5K_PCICFG_SPWR_DN 0x00010000 /* Mask for power status */
#define AR5K_PCICFG_LEDMODE 0x000e0000 /* Ledmode [5211+] */
#define AR5K_PCICFG_LEDMODE_PROP 0x00000000 /* Blink on standard traffic [5211+] */
#define AR5K_PCICFG_LEDMODE_PROM 0x00020000 /* Default mode (blink on any traffic) [5211+] */
#define AR5K_PCICFG_LEDMODE_PWR 0x00040000 /* Some other blinking mode (?) [5211+] */
#define AR5K_PCICFG_LEDMODE_RAND 0x00060000 /* Random blinking (?) [5211+] */
-#define AR5K_PCICFG_LEDBLINK 0x00700000
+#define AR5K_PCICFG_LEDBLINK 0x00700000 /* Led blink rate */
#define AR5K_PCICFG_LEDBLINK_S 20
-#define AR5K_PCICFG_LEDSLOW 0x00800000 /* Slow led blink rate (?) [5211+] */
+#define AR5K_PCICFG_LEDSLOW 0x00800000 /* Slowest led blink rate [5211+] */
#define AR5K_PCICFG_LEDSTATE \
(AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE | \
AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW)
+#define AR5K_PCICFG_SLEEP_CLOCK_RATE 0x03000000 /* Sleep clock rate (field) */
/*
* "General Purpose Input/Output" (GPIO) control register
@@ -947,7 +1021,7 @@
#define AR5K_EEPROM_VERSION_4_4 0x4004
#define AR5K_EEPROM_VERSION_4_5 0x4005
#define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */
-#define AR5K_EEPROM_VERSION_4_7 0x3007
+#define AR5K_EEPROM_VERSION_4_7 0x4007
#define AR5K_EEPROM_MODE_11A 0
#define AR5K_EEPROM_MODE_11B 1
@@ -1023,10 +1097,14 @@
#define AR5K_EEPROM_STAT_WRDONE 0x00000008 /* EEPROM write successful */
/*
- * EEPROM config register (?)
+ * EEPROM config register
*/
-#define AR5K_EEPROM_CFG 0x6010
-
+#define AR5K_EEPROM_CFG 0x6010 /* Register Addres */
+#define AR5K_EEPROM_CFG_SIZE_OVR 0x00000001
+#define AR5K_EEPROM_CFG_WR_WAIT_DIS 0x00000004 /* Disable write wait */
+#define AR5K_EEPROM_CFG_CLK_RATE 0x00000018 /* Clock rate */
+#define AR5K_EEPROM_CFG_PROT_KEY 0x00ffff00 /* Protectio key */
+#define AR5K_EEPROM_CFG_LIND_EN 0x01000000 /* Enable length indicator (?) */
/*
@@ -1050,7 +1128,7 @@
#define AR5K_STA_ID1 0x8004 /* Register Address */
#define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */
#define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */
-#define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting (?) */
+#define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */
#define AR5K_STA_ID1_NO_KEYSRCH 0x00080000 /* No key search */
#define AR5K_STA_ID1_NO_PSPOLL 0x00100000 /* No power save polling [5210] */
#define AR5K_STA_ID1_PCF_5211 0x00100000 /* Enable PCF on [5211+] */
@@ -1059,9 +1137,13 @@
AR5K_STA_ID1_PCF_5210 : AR5K_STA_ID1_PCF_5211)
#define AR5K_STA_ID1_DEFAULT_ANTENNA 0x00200000 /* Use default antenna */
#define AR5K_STA_ID1_DESC_ANTENNA 0x00400000 /* Update antenna from descriptor */
-#define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS (?) */
-#define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS (?) */
+#define AR5K_STA_ID1_RTS_DEF_ANTENNA 0x00800000 /* Use default antenna for RTS */
+#define AR5K_STA_ID1_ACKCTS_6MB 0x01000000 /* Use 6Mbit/s for ACK/CTS */
#define AR5K_STA_ID1_BASE_RATE_11B 0x02000000 /* Use 11b base rate (for ACK/CTS ?) [5211+] */
+#define AR5K_STA_ID1_SELF_GEN_SECTORE 0x04000000 /* Self generate sectore (?) */
+#define AR5K_STA_ID1_CRYPT_MIC_EN 0x08000000 /* Enable MIC */
+#define AR5K_STA_ID1_KEYSRCH_MODE 0x10000000 /* Keysearch mode (?) */
+#define AR5K_STA_ID1_PRESERVE_SEQ_NUM 0x20000000 /* Preserve sequence number */
/*
* First BSSID register (MAC address, lower 32bits)
@@ -1117,7 +1199,7 @@
*
* Retry limit register for 5210 (no QCU/DCU so it's done in PCU)
*/
-#define AR5K_NODCU_RETRY_LMT 0x801c /*Register Address */
+#define AR5K_NODCU_RETRY_LMT 0x801c /* Register Address */
#define AR5K_NODCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */
#define AR5K_NODCU_RETRY_LMT_SH_RETRY_S 0
#define AR5K_NODCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry mask */
@@ -1136,9 +1218,9 @@
#define AR5K_USEC_5211 0x801c /* Register Address [5211+] */
#define AR5K_USEC (ah->ah_version == AR5K_AR5210 ? \
AR5K_USEC_5210 : AR5K_USEC_5211)
-#define AR5K_USEC_1 0x0000007f
+#define AR5K_USEC_1 0x0000007f /* clock cycles for 1us */
#define AR5K_USEC_1_S 0
-#define AR5K_USEC_32 0x00003f80
+#define AR5K_USEC_32 0x00003f80 /* clock cycles for 1us while on 32Mhz clock */
#define AR5K_USEC_32_S 7
#define AR5K_USEC_TX_LATENCY_5211 0x007fc000
#define AR5K_USEC_TX_LATENCY_5211_S 14
@@ -1152,16 +1234,16 @@
/*
* PCU beacon control register
*/
-#define AR5K_BEACON_5210 0x8024
-#define AR5K_BEACON_5211 0x8020
+#define AR5K_BEACON_5210 0x8024 /*Register Address [5210] */
+#define AR5K_BEACON_5211 0x8020 /*Register Address [5211+] */
#define AR5K_BEACON (ah->ah_version == AR5K_AR5210 ? \
AR5K_BEACON_5210 : AR5K_BEACON_5211)
-#define AR5K_BEACON_PERIOD 0x0000ffff
+#define AR5K_BEACON_PERIOD 0x0000ffff /* Mask for beacon period */
#define AR5K_BEACON_PERIOD_S 0
-#define AR5K_BEACON_TIM 0x007f0000
+#define AR5K_BEACON_TIM 0x007f0000 /* Mask for TIM offset */
#define AR5K_BEACON_TIM_S 16
-#define AR5K_BEACON_ENABLE 0x00800000
-#define AR5K_BEACON_RESET_TSF 0x01000000
+#define AR5K_BEACON_ENABLE 0x00800000 /* Enable beacons */
+#define AR5K_BEACON_RESET_TSF 0x01000000 /* Force TSF reset */
/*
* CFP period register
@@ -1234,7 +1316,6 @@
/*
* Receive filter register
- * TODO: Get these out of ar5xxx.h on ath5k
*/
#define AR5K_RX_FILTER_5210 0x804c /* Register Address [5210] */
#define AR5K_RX_FILTER_5211 0x803c /* Register Address [5211+] */
@@ -1307,11 +1388,11 @@
#define AR5K_DIAG_SW_5211 0x8048 /* Register Address [5211+] */
#define AR5K_DIAG_SW (ah->ah_version == AR5K_AR5210 ? \
AR5K_DIAG_SW_5210 : AR5K_DIAG_SW_5211)
-#define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001
-#define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs (?) */
-#define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs (?) */
-#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption (?) */
-#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption (?) */
+#define AR5K_DIAG_SW_DIS_WEP_ACK 0x00000001 /* Disable ACKs if WEP key is invalid */
+#define AR5K_DIAG_SW_DIS_ACK 0x00000002 /* Disable ACKs */
+#define AR5K_DIAG_SW_DIS_CTS 0x00000004 /* Disable CTSs */
+#define AR5K_DIAG_SW_DIS_ENC 0x00000008 /* Disable encryption */
+#define AR5K_DIAG_SW_DIS_DEC 0x00000010 /* Disable decryption */
#define AR5K_DIAG_SW_DIS_TX 0x00000020 /* Disable transmit [5210] */
#define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable recieve */
#define AR5K_DIAG_SW_DIS_RX_5211 0x00000020
@@ -1329,13 +1410,13 @@
#define AR5K_DIAG_SW_CHAN_INFO_5211 0x00000100
#define AR5K_DIAG_SW_CHAN_INFO (ah->ah_version == AR5K_AR5210 ? \
AR5K_DIAG_SW_CHAN_INFO_5210 : AR5K_DIAG_SW_CHAN_INFO_5211)
-#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211 0x00000200 /* Scrambler seed (?) */
+#define AR5K_DIAG_SW_EN_SCRAM_SEED_5211 0x00000200 /* Enable scrambler seed */
#define AR5K_DIAG_SW_EN_SCRAM_SEED_5210 0x00000400
#define AR5K_DIAG_SW_EN_SCRAM_SEED (ah->ah_version == AR5K_AR5210 ? \
AR5K_DIAG_SW_EN_SCRAM_SEED_5210 : AR5K_DIAG_SW_EN_SCRAM_SEED_5211)
#define AR5K_DIAG_SW_ECO_ENABLE 0x00000400 /* [5211+] */
#define AR5K_DIAG_SW_SCVRAM_SEED 0x0003f800 /* [5210] */
-#define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask (?) */
+#define AR5K_DIAG_SW_SCRAM_SEED_M 0x0001fc00 /* Scrambler seed mask */
#define AR5K_DIAG_SW_SCRAM_SEED_S 10
#define AR5K_DIAG_SW_DIS_SEQ_INC 0x00040000 /* Disable seqnum increment (?)[5210] */
#define AR5K_DIAG_SW_FRAME_NV0_5210 0x00080000
@@ -1344,6 +1425,7 @@
AR5K_DIAG_SW_FRAME_NV0_5210 : AR5K_DIAG_SW_FRAME_NV0_5211)
#define AR5K_DIAG_SW_OBSPT_M 0x000c0000
#define AR5K_DIAG_SW_OBSPT_S 18
+/* more bits */
/*
* TSF (clock) register (lower 32 bits)
@@ -1369,15 +1451,34 @@
/*
* ADDAC test register [5211+]
*/
-#define AR5K_ADDAC_TEST 0x8054
-#define AR5K_ADDAC_TEST_TXCONT 0x00000001
+#define AR5K_ADDAC_TEST 0x8054 /* Register Address */
+#define AR5K_ADDAC_TEST_TXCONT 0x00000001 /* Test continuous tx */
+#define AR5K_ADDAC_TEST_TST_MODE 0x00000002 /* Test mode */
+#define AR5K_ADDAC_TEST_LOOP_EN 0x00000004 /* Enable loop */
+#define AR5K_ADDAC_TEST_LOOP_LEN 0x00000008 /* Loop length (field) */
+#define AR5K_ADDAC_TEST_USE_U8 0x00004000 /* Use upper 8 bits */
+#define AR5K_ADDAC_TEST_MSB 0x00008000 /* State of MSB */
+#define AR5K_ADDAC_TEST_TRIG_SEL 0x00010000 /* Trigger select */
+#define AR5K_ADDAC_TEST_TRIG_PTY 0x00020000 /* Trigger polarity */
+#define AR5K_ADDAC_TEST_RXCONT 0x00040000 /* Continuous capture */
+#define AR5K_ADDAC_TEST_CAPTURE 0x00080000 /* Begin capture */
+#define AR5K_ADDAC_TEST_TST_ARM 0x00100000 /* Test ARM (Adaptive Radio Mode ?) */
/*
* Default antenna register [5211+]
*/
#define AR5K_DEFAULT_ANTENNA 0x8058
+/*
+ * Frame control QoS mask register (?) [5211+]
+ * (FC_QOS_MASK)
+ */
+#define AR5K_FRAME_CTL_QOSM 0x805c
+/*
+ * Seq mask register (?) [5211+]
+ */
+#define AR5K_SEQ_MASK 0x8060
/*
* Retry count register [5210]
@@ -1449,124 +1550,242 @@
/*
* XR (eXtended Range) mode register
*/
-#define AR5K_XRMODE 0x80c0
-#define AR5K_XRMODE_POLL_TYPE_M 0x0000003f
+#define AR5K_XRMODE 0x80c0 /* Register Address */
+#define AR5K_XRMODE_POLL_TYPE_M 0x0000003f /* Mask for Poll type (?) */
#define AR5K_XRMODE_POLL_TYPE_S 0
-#define AR5K_XRMODE_POLL_SUBTYPE_M 0x0000003c
+#define AR5K_XRMODE_POLL_SUBTYPE_M 0x0000003c /* Mask for Poll subtype (?) */
#define AR5K_XRMODE_POLL_SUBTYPE_S 2
-#define AR5K_XRMODE_POLL_WAIT_ALL 0x00000080
-#define AR5K_XRMODE_SIFS_DELAY 0x000fff00
-#define AR5K_XRMODE_FRAME_HOLD_M 0xfff00000
+#define AR5K_XRMODE_POLL_WAIT_ALL 0x00000080 /* Wait for poll */
+#define AR5K_XRMODE_SIFS_DELAY 0x000fff00 /* Mask for SIFS delay */
+#define AR5K_XRMODE_FRAME_HOLD_M 0xfff00000 /* Mask for frame hold (?) */
#define AR5K_XRMODE_FRAME_HOLD_S 20
/*
* XR delay register
*/
-#define AR5K_XRDELAY 0x80c4
-#define AR5K_XRDELAY_SLOT_DELAY_M 0x0000ffff
+#define AR5K_XRDELAY 0x80c4 /* Register Address */
+#define AR5K_XRDELAY_SLOT_DELAY_M 0x0000ffff /* Mask for slot delay */
#define AR5K_XRDELAY_SLOT_DELAY_S 0
-#define AR5K_XRDELAY_CHIRP_DELAY_M 0xffff0000
+#define AR5K_XRDELAY_CHIRP_DELAY_M 0xffff0000 /* Mask for CHIRP data delay */
#define AR5K_XRDELAY_CHIRP_DELAY_S 16
/*
* XR timeout register
*/
-#define AR5K_XRTIMEOUT 0x80c8
-#define AR5K_XRTIMEOUT_CHIRP_M 0x0000ffff
+#define AR5K_XRTIMEOUT 0x80c8 /* Register Address */
+#define AR5K_XRTIMEOUT_CHIRP_M 0x0000ffff /* Mask for CHIRP timeout */
#define AR5K_XRTIMEOUT_CHIRP_S 0
-#define AR5K_XRTIMEOUT_POLL_M 0xffff0000
+#define AR5K_XRTIMEOUT_POLL_M 0xffff0000 /* Mask for Poll timeout */
#define AR5K_XRTIMEOUT_POLL_S 16
/*
* XR chirp register
*/
-#define AR5K_XRCHIRP 0x80cc
-#define AR5K_XRCHIRP_SEND 0x00000001
-#define AR5K_XRCHIRP_GAP 0xffff0000
+#define AR5K_XRCHIRP 0x80cc /* Register Address */
+#define AR5K_XRCHIRP_SEND 0x00000001 /* Send CHIRP */
+#define AR5K_XRCHIRP_GAP 0xffff0000 /* Mask for CHIRP gap (?) */
/*
* XR stomp register
*/
-#define AR5K_XRSTOMP 0x80d0
-#define AR5K_XRSTOMP_TX 0x00000001
-#define AR5K_XRSTOMP_RX_ABORT 0x00000002
-#define AR5K_XRSTOMP_RSSI_THRES 0x0000ff00
+#define AR5K_XRSTOMP 0x80d0 /* Register Address */
+#define AR5K_XRSTOMP_TX 0x00000001 /* Stomp Tx (?) */
+#define AR5K_XRSTOMP_RX 0x00000002 /* Stomp Rx (?) */
+#define AR5K_XRSTOMP_TX_RSSI 0x00000004 /* Stomp Tx RSSI (?) */
+#define AR5K_XRSTOMP_TX_BSSID 0x00000008 /* Stomp Tx BSSID (?) */
+#define AR5K_XRSTOMP_DATA 0x00000010 /* Stomp data (?)*/
+#define AR5K_XRSTOMP_RSSI_THRES 0x0000ff00 /* Mask for XR RSSI threshold */
/*
* First enhanced sleep register
*/
-#define AR5K_SLEEP0 0x80d4
-#define AR5K_SLEEP0_NEXT_DTIM 0x0007ffff
+#define AR5K_SLEEP0 0x80d4 /* Register Address */
+#define AR5K_SLEEP0_NEXT_DTIM 0x0007ffff /* Mask for next DTIM (?) */
#define AR5K_SLEEP0_NEXT_DTIM_S 0
-#define AR5K_SLEEP0_ASSUME_DTIM 0x00080000
-#define AR5K_SLEEP0_ENH_SLEEP_EN 0x00100000
-#define AR5K_SLEEP0_CABTO 0xff000000
+#define AR5K_SLEEP0_ASSUME_DTIM 0x00080000 /* Assume DTIM */
+#define AR5K_SLEEP0_ENH_SLEEP_EN 0x00100000 /* Enable enchanced sleep control */
+#define AR5K_SLEEP0_CABTO 0xff000000 /* Mask for CAB Time Out */
#define AR5K_SLEEP0_CABTO_S 24
/*
* Second enhanced sleep register
*/
-#define AR5K_SLEEP1 0x80d8
-#define AR5K_SLEEP1_NEXT_TIM 0x0007ffff
+#define AR5K_SLEEP1 0x80d8 /* Register Address */
+#define AR5K_SLEEP1_NEXT_TIM 0x0007ffff /* Mask for next TIM (?) */
#define AR5K_SLEEP1_NEXT_TIM_S 0
-#define AR5K_SLEEP1_BEACON_TO 0xff000000
+#define AR5K_SLEEP1_BEACON_TO 0xff000000 /* Mask for Beacon Time Out */
#define AR5K_SLEEP1_BEACON_TO_S 24
/*
* Third enhanced sleep register
*/
-#define AR5K_SLEEP2 0x80dc
-#define AR5K_SLEEP2_TIM_PER 0x0000ffff
+#define AR5K_SLEEP2 0x80dc /* Register Address */
+#define AR5K_SLEEP2_TIM_PER 0x0000ffff /* Mask for TIM period (?) */
#define AR5K_SLEEP2_TIM_PER_S 0
-#define AR5K_SLEEP2_DTIM_PER 0xffff0000
+#define AR5K_SLEEP2_DTIM_PER 0xffff0000 /* Mask for DTIM period (?) */
#define AR5K_SLEEP2_DTIM_PER_S 16
/*
* BSSID mask registers
*/
-#define AR5K_BSS_IDM0 0x80e0
-#define AR5K_BSS_IDM1 0x80e4
+#define AR5K_BSS_IDM0 0x80e0 /* Upper bits */
+#define AR5K_BSS_IDM1 0x80e4 /* Lower bits */
/*
* TX power control (TPC) register
+ *
+ * XXX: PCDAC steps (0.5dbm) or DBM ?
+ *
+ * XXX: Mask changes for newer chips to 7f
+ * like tx power table ?
*/
-#define AR5K_TXPC 0x80e8
-#define AR5K_TXPC_ACK_M 0x0000003f
+#define AR5K_TXPC 0x80e8 /* Register Address */
+#define AR5K_TXPC_ACK_M 0x0000003f /* Mask for ACK tx power */
#define AR5K_TXPC_ACK_S 0
-#define AR5K_TXPC_CTS_M 0x00003f00
+#define AR5K_TXPC_CTS_M 0x00003f00 /* Mask for CTS tx power */
#define AR5K_TXPC_CTS_S 8
-#define AR5K_TXPC_CHIRP_M 0x003f0000
+#define AR5K_TXPC_CHIRP_M 0x003f0000 /* Mask for CHIRP tx power */
#define AR5K_TXPC_CHIRP_S 22
/*
* Profile count registers
*/
-#define AR5K_PROFCNT_TX 0x80ec
-#define AR5K_PROFCNT_RX 0x80f0
-#define AR5K_PROFCNT_RXCLR 0x80f4
-#define AR5K_PROFCNT_CYCLE 0x80f8
+#define AR5K_PROFCNT_TX 0x80ec /* Tx count */
+#define AR5K_PROFCNT_RX 0x80f0 /* Rx count */
+#define AR5K_PROFCNT_RXCLR 0x80f4 /* Clear Rx count */
+#define AR5K_PROFCNT_CYCLE 0x80f8 /* Cycle count (?) */
+
+/*
+ * Quiet (period) control registers (?)
+ */
+#define AR5K_QUIET_CTL1 0x80fc /* Register Address */
+#define AR5K_QUIET_CTL1_NEXT_QT 0x0000ffff /* Mask for next quiet (period?) (?) */
+#define AR5K_QUIET_CTL1_QT_EN 0x00010000 /* Enable quiet (period?) */
+#define AR5K_QUIET_CTL2 0x8100 /* Register Address */
+#define AR5K_QUIET_CTL2_QT_PER 0x0000ffff /* Mask for quiet period (?) */
+#define AR5K_QUIET_CTL2_QT_DUR 0xffff0000 /* Mask for quiet duration (?) */
/*
* TSF parameter register
*/
-#define AR5K_TSF_PARM 0x8104
-#define AR5K_TSF_PARM_INC_M 0x000000ff
+#define AR5K_TSF_PARM 0x8104 /* Register Address */
+#define AR5K_TSF_PARM_INC_M 0x000000ff /* Mask for TSF increment */
#define AR5K_TSF_PARM_INC_S 0
/*
+ * QoS register (?)
+ */
+#define AR5K_QOS 0x8108 /* Register Address */
+#define AR5K_QOS_NOACK_2BIT_VALUES 0x00000000 /* (field) */
+#define AR5K_QOS_NOACK_BIT_OFFSET 0x00000020 /* (field) */
+#define AR5K_QOS_NOACK_BYTE_OFFSET 0x00000080 /* (field) */
+
+/*
* PHY error filter register
*/
#define AR5K_PHY_ERR_FIL 0x810c
-#define AR5K_PHY_ERR_FIL_RADAR 0x00000020
-#define AR5K_PHY_ERR_FIL_OFDM 0x00020000
-#define AR5K_PHY_ERR_FIL_CCK 0x02000000
+#define AR5K_PHY_ERR_FIL_RADAR 0x00000020 /* Radar signal */
+#define AR5K_PHY_ERR_FIL_OFDM 0x00020000 /* OFDM false detect (ANI) */
+#define AR5K_PHY_ERR_FIL_CCK 0x02000000 /* CCK false detect (ANI) */
+
+/*
+ * XR latency register
+ */
+#define AR5K_XRLAT_TX 0x8110
/*
- * Rate duration register
+ * ACK SIFS register
+ */
+#define AR5K_ACKSIFS 0x8114 /* Register Address */
+#define AR5K_ACKSIFS_INC 0x00000000 /* ACK SIFS Increment (field) */
+
+/*
+ * MIC QoS control register (?)
+ */
+#define AR5K_MIC_QOS_CTL 0x8118 /* Register Address */
+#define AR5K_MIC_QOS_CTL_0 0x00000001 /* MIC QoS control 0 (?) */
+#define AR5K_MIC_QOS_CTL_1 0x00000004 /* MIC QoS control 1 (?) */
+#define AR5K_MIC_QOS_CTL_2 0x00000010 /* MIC QoS control 2 (?) */
+#define AR5K_MIC_QOS_CTL_3 0x00000040 /* MIC QoS control 3 (?) */
+#define AR5K_MIC_QOS_CTL_4 0x00000100 /* MIC QoS control 4 (?) */
+#define AR5K_MIC_QOS_CTL_5 0x00000400 /* MIC QoS control 5 (?) */
+#define AR5K_MIC_QOS_CTL_6 0x00001000 /* MIC QoS control 6 (?) */
+#define AR5K_MIC_QOS_CTL_7 0x00004000 /* MIC QoS control 7 (?) */
+#define AR5K_MIC_QOS_CTL_MQ_EN 0x00010000 /* Enable MIC QoS */
+
+/*
+ * MIC QoS select register (?)
+ */
+#define AR5K_MIC_QOS_SEL 0x811c
+#define AR5K_MIC_QOS_SEL_0 0x00000001
+#define AR5K_MIC_QOS_SEL_1 0x00000010
+#define AR5K_MIC_QOS_SEL_2 0x00000100
+#define AR5K_MIC_QOS_SEL_3 0x00001000
+#define AR5K_MIC_QOS_SEL_4 0x00010000
+#define AR5K_MIC_QOS_SEL_5 0x00100000
+#define AR5K_MIC_QOS_SEL_6 0x01000000
+#define AR5K_MIC_QOS_SEL_7 0x10000000
+
+/*
+ * Misc mode control register (?)
+ */
+#define AR5K_MISC_MODE 0x8120 /* Register Address */
+#define AR5K_MISC_MODE_FBSSID_MATCH 0x00000001 /* Force BSSID match */
+#define AR5K_MISC_MODE_ACKSIFS_MEM 0x00000002 /* ACK SIFS memory (?) */
+/* more bits */
+
+/*
+ * OFDM Filter counter
+ */
+#define AR5K_OFDM_FIL_CNT 0x8124
+
+/*
+ * CCK Filter counter
+ */
+#define AR5K_CCK_FIL_CNT 0x8128
+
+/*
+ * PHY Error Counters (?)
+ */
+#define AR5K_PHYERR_CNT1 0x812c
+#define AR5K_PHYERR_CNT1_MASK 0x8130
+
+#define AR5K_PHYERR_CNT2 0x8134
+#define AR5K_PHYERR_CNT2_MASK 0x8138
+
+/*
+ * TSF Threshold register (?)
+ */
+#define AR5K_TSF_THRES 0x813c
+
+/*
+ * Rate -> ACK SIFS mapping table (32 entries)
+ */
+#define AR5K_RATE_ACKSIFS_BASE 0x8680 /* Register Address */
+#define AR5K_RATE_ACKSIFS(_n) (AR5K_RATE_ACKSIFS_BSE + ((_n) << 2))
+#define AR5K_RATE_ACKSIFS_NORMAL 0x00000001 /* Normal SIFS (field) */
+#define AR5K_RATE_ACKSIFS_TURBO 0x00000400 /* Turbo SIFS (field) */
+
+/*
+ * Rate -> duration mapping table (32 entries)
*/
#define AR5K_RATE_DUR_BASE 0x8700
#define AR5K_RATE_DUR(_n) (AR5K_RATE_DUR_BASE + ((_n) << 2))
+/*
+ * Rate -> db mapping table
+ * (8 entries, each one has 4 8bit fields)
+ */
+#define AR5K_RATE2DB_BASE 0x87c0
+#define AR5K_RATE2DB(_n) (AR5K_RATE2DB_BASE + ((_n) << 2))
+
+/*
+ * db -> Rate mapping table
+ * (8 entries, each one has 4 8bit fields)
+ */
+#define AR5K_DB2RATE_BASE 0x87e0
+#define AR5K_DB2RATE(_n) (AR5K_DB2RATE_BASE + ((_n) << 2))
+
/*===5212 end===*/
/*
@@ -1613,12 +1832,34 @@
/*===PHY REGISTERS===*/
/*
- * PHY register
+ * PHY registers start
*/
#define AR5K_PHY_BASE 0x9800
#define AR5K_PHY(_n) (AR5K_PHY_BASE + ((_n) << 2))
-#define AR5K_PHY_SHIFT_2GHZ 0x00004007
-#define AR5K_PHY_SHIFT_5GHZ 0x00000007
+
+/*
+ * TST_2 (Misc config parameters)
+ */
+#define AR5K_PHY_TST2 0x9800 /* Register Address */
+#define AR5K_PHY_TST2_TRIG_SEL 0x00000001 /* Trigger select (?) (field ?) */
+#define AR5K_PHY_TST2_TRIG 0x00000010 /* Trigger (?) (field ?) */
+#define AR5K_PHY_TST2_CBUS_MODE 0x00000100 /* Cardbus mode (?) */
+/* bit reserved */
+#define AR5K_PHY_TST2_CLK32 0x00000400 /* CLK_OUT is CLK32 (32Khz external) */
+#define AR5K_PHY_TST2_CHANCOR_DUMP_EN 0x00000800 /* Enable Chancor dump (?) */
+#define AR5K_PHY_TST2_EVEN_CHANCOR_DUMP 0x00001000 /* Even Chancor dump (?) */
+#define AR5K_PHY_TST2_RFSILENT_EN 0x00002000 /* Enable RFSILENT */
+#define AR5K_PHY_TST2_ALT_RFDATA 0x00004000 /* Alternate RFDATA (5-2GHz switch) */
+#define AR5K_PHY_TST2_MINI_OBS_EN 0x00008000 /* Enable mini OBS (?) */
+#define AR5K_PHY_TST2_RX2_IS_RX5_INV 0x00010000 /* 2GHz rx path is the 5GHz path inverted (?) */
+#define AR5K_PHY_TST2_SLOW_CLK160 0x00020000 /* Slow CLK160 (?) */
+#define AR5K_PHY_TST2_AGC_OBS_SEL_3 0x00040000 /* AGC OBS Select 3 (?) */
+#define AR5K_PHY_TST2_BBB_OBS_SEL 0x00080000 /* BB OBS Select (field ?) */
+#define AR5K_PHY_TST2_ADC_OBS_SEL 0x00800000 /* ADC OBS Select (field ?) */
+#define AR5K_PHY_TST2_RX_CLR_SEL 0x08000000 /* RX Clear Select (?) */
+#define AR5K_PHY_TST2_FORCE_AGC_CLR 0x10000000 /* Force AGC clear (?) */
+#define AR5K_PHY_SHIFT_2GHZ 0x00004007 /* Used to access 2GHz radios */
+#define AR5K_PHY_SHIFT_5GHZ 0x00000007 /* Used to access 5GHz radios (default) */
/*
* PHY frame control register [5110] /turbo mode register [5111+]
@@ -1630,18 +1871,21 @@
* a "turbo mode register" for 5110. We treat this one as
* a frame control register for 5110 below.
*/
-#define AR5K_PHY_TURBO 0x9804
-#define AR5K_PHY_TURBO_MODE 0x00000001
-#define AR5K_PHY_TURBO_SHORT 0x00000002
+#define AR5K_PHY_TURBO 0x9804 /* Register Address */
+#define AR5K_PHY_TURBO_MODE 0x00000001 /* Enable turbo mode */
+#define AR5K_PHY_TURBO_SHORT 0x00000002 /* Short mode (20Mhz channels) (?) */
/*
* PHY agility command register
+ * (aka TST_1)
*/
-#define AR5K_PHY_AGC 0x9808
-#define AR5K_PHY_AGC_DISABLE 0x08000000
+#define AR5K_PHY_AGC 0x9808 /* Register Address */
+#define AR5K_PHY_TST1 0x9808
+#define AR5K_PHY_AGC_DISABLE 0x08000000 /* Disable AGC to A2 (?)*/
+#define AR5K_PHY_TST1_TXHOLD 0x00003800 /* Set tx hold (?) */
/*
- * PHY timing register [5112+]
+ * PHY timing register 3 [5112+]
*/
#define AR5K_PHY_TIMING_3 0x9814
#define AR5K_PHY_TIMING_3_DSC_MAN 0xfffe0000
@@ -1657,26 +1901,81 @@
/*
* PHY activation register
*/
-#define AR5K_PHY_ACT 0x981c
-#define AR5K_PHY_ACT_ENABLE 0x00000001
-#define AR5K_PHY_ACT_DISABLE 0x00000002
+#define AR5K_PHY_ACT 0x981c /* Register Address */
+#define AR5K_PHY_ACT_ENABLE 0x00000001 /* Activate PHY */
+#define AR5K_PHY_ACT_DISABLE 0x00000002 /* Deactivate PHY */
+
+/*
+ * PHY RF control registers
+ * (i think these are delay times,
+ * these calibration values exist
+ * in EEPROM)
+ */
+#define AR5K_PHY_RF_CTL2 0x9824 /* Register Address */
+#define AR5K_PHY_RF_CTL2_TXF2TXD_START 0x0000000f /* Mask for TX frame to TX d(esc?) start */
+
+#define AR5K_PHY_RF_CTL3 0x9828 /* Register Address */
+#define AR5K_PHY_RF_CTL3_TXE2XLNA_ON 0x0000000f /* Mask for TX end to XLNA on */
+
+#define AR5K_PHY_RF_CTL4 0x9834 /* Register Address */
+#define AR5K_PHY_RF_CTL4_TXF2XPA_A_ON 0x00000001 /* TX frame to XPA A on (field) */
+#define AR5K_PHY_RF_CTL4_TXF2XPA_B_ON 0x00000100 /* TX frame to XPA B on (field) */
+#define AR5K_PHY_RF_CTL4_TXE2XPA_A_OFF 0x00010000 /* TX end to XPA A off (field) */
+#define AR5K_PHY_RF_CTL4_TXE2XPA_B_OFF 0x01000000 /* TX end to XPA B off (field) */
+
+/*
+ * Pre-Amplifier control register
+ * (XPA -> external pre-amplifier)
+ */
+#define AR5K_PHY_PA_CTL 0x9838 /* Register Address */
+#define AR5K_PHY_PA_CTL_XPA_A_HI 0x00000001 /* XPA A high (?) */
+#define AR5K_PHY_PA_CTL_XPA_B_HI 0x00000002 /* XPA B high (?) */
+#define AR5K_PHY_PA_CTL_XPA_A_EN 0x00000004 /* Enable XPA A */
+#define AR5K_PHY_PA_CTL_XPA_B_EN 0x00000008 /* Enable XPA B */
+
+/*
+ * PHY settling register
+ */
+#define AR5K_PHY_SETTLING 0x9844 /* Register Address */
+#define AR5K_PHY_SETTLING_AGC 0x0000007f /* Mask for AGC settling time */
+#define AR5K_PHY_SETTLING_SWITCH 0x00003f80 /* Mask for Switch settlig time */
+
+/*
+ * PHY Gain registers
+ */
+#define AR5K_PHY_GAIN 0x9848 /* Register Address */
+#define AR5K_PHY_GAIN_TXRX_ATTEN 0x0003f000 /* Mask for TX-RX Attenuation */
+
+#define AR5K_PHY_GAIN_OFFSET 0x984c /* Register Address */
+#define AR5K_PHY_GAIN_OFFSET_RXTX_FLAG 0x00020000 /* RX-TX flag (?) */
+
+/*
+ * Desired size register
+ * (for more infos read ANI patent)
+ */
+#define AR5K_PHY_DESIRED_SIZE 0x9850 /* Register Address */
+#define AR5K_PHY_DESIRED_SIZE_ADC 0x000000ff /* Mask for ADC desired size */
+#define AR5K_PHY_DESIRED_SIZE_PGA 0x0000ff00 /* Mask for PGA desired size */
+#define AR5K_PHY_DESIRED_SIZE_TOT 0x0ff00000 /* Mask for Total desired size (?) */
/*
* PHY signal register
+ * (for more infos read ANI patent)
*/
-#define AR5K_PHY_SIG 0x9858
-#define AR5K_PHY_SIG_FIRSTEP 0x0003f000
+#define AR5K_PHY_SIG 0x9858 /* Register Address */
+#define AR5K_PHY_SIG_FIRSTEP 0x0003f000 /* Mask for FIRSTEP */
#define AR5K_PHY_SIG_FIRSTEP_S 12
-#define AR5K_PHY_SIG_FIRPWR 0x03fc0000
+#define AR5K_PHY_SIG_FIRPWR 0x03fc0000 /* Mask for FIPWR */
#define AR5K_PHY_SIG_FIRPWR_S 18
/*
* PHY coarse agility control register
+ * (for more infos read ANI patent)
*/
-#define AR5K_PHY_AGCCOARSE 0x985c
-#define AR5K_PHY_AGCCOARSE_LO 0x00007f80
+#define AR5K_PHY_AGCCOARSE 0x985c /* Register Address */
+#define AR5K_PHY_AGCCOARSE_LO 0x00007f80 /* Mask for AGC Coarse low */
#define AR5K_PHY_AGCCOARSE_LO_S 7
-#define AR5K_PHY_AGCCOARSE_HI 0x003f8000
+#define AR5K_PHY_AGCCOARSE_HI 0x003f8000 /* Mask for AGC Coarse high */
#define AR5K_PHY_AGCCOARSE_HI_S 15
/*
@@ -1689,12 +1988,13 @@
/*
* PHY noise floor status register
*/
-#define AR5K_PHY_NF 0x9864
-#define AR5K_PHY_NF_M 0x000001ff
-#define AR5K_PHY_NF_ACTIVE 0x00000100
+#define AR5K_PHY_NF 0x9864 /* Register address */
+#define AR5K_PHY_NF_M 0x000001ff /* Noise floor mask */
+#define AR5K_PHY_NF_ACTIVE 0x00000100 /* Noise floor calibration still active */
#define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M)
#define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1)
#define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9))
+#define AR5K_PHY_NF_THRESH62 0x00001000 /* Thresh62 -check ANI patent- (field) */
/*
* PHY ADC saturation register [5110]
@@ -1706,6 +2006,30 @@
#define AR5K_PHY_ADCSAT_THR_S 5
/*
+ * PHY Weak ofdm signal detection threshold registers (ANI) [5212+]
+ */
+
+/* High thresholds */
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR 0x9868
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT 0x0000001f
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT_S 0
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1 0x00fe0000
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M1_S 17
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2 0x7f000000
+#define AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_S 24
+
+/* Low thresholds */
+#define AR5K_PHY_WEAK_OFDM_LOW_THR 0x986c
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN 0x00000001
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT 0x00003f00
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT_S 8
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1 0x001fc000
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M1_S 14
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2 0x0fe00000
+#define AR5K_PHY_WEAK_OFDM_LOW_THR_M2_S 21
+
+
+/*
* PHY sleep registers [5112+]
*/
#define AR5K_PHY_SCR 0x9870
@@ -1730,6 +2054,8 @@
AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212)
#define AR5K_PHY_PLL_RF5111 0x00000000
#define AR5K_PHY_PLL_RF5112 0x00000040
+#define AR5K_PHY_PLL_HALF_RATE 0x00000100
+#define AR5K_PHY_PLL_QUARTER_RATE 0x00000200
/*
* RF Buffer register
@@ -1792,23 +2118,74 @@
#define AR5K_PHY_RFSTG_DISABLE 0x00000021
/*
+ * PHY Antenna control register
+ */
+#define AR5K_PHY_ANT_CTL 0x9910 /* Register Address */
+#define AR5K_PHY_ANT_CTL_TXRX_EN 0x00000001 /* Enable TX/RX (?) */
+#define AR5K_PHY_ANT_CTL_SECTORED_ANT 0x00000004 /* Sectored Antenna */
+#define AR5K_PHY_ANT_CTL_HITUNE5 0x00000008 /* Hitune5 (?) */
+#define AR5K_PHY_ANT_CTL_SWTABLE_IDLE 0x00000010 /* Switch table idle (?) */
+
+/*
* PHY receiver delay register [5111+]
*/
-#define AR5K_PHY_RX_DELAY 0x9914
-#define AR5K_PHY_RX_DELAY_M 0x00003fff
+#define AR5K_PHY_RX_DELAY 0x9914 /* Register Address */
+#define AR5K_PHY_RX_DELAY_M 0x00003fff /* Mask for RX activate to receive delay (/100ns) */
+
+/*
+ * PHY max rx length register (?) [5111]
+ */
+#define AR5K_PHY_MAX_RX_LEN 0x991c
/*
- * PHY timing I(nphase) Q(adrature) control register [5111+]
+ * PHY timing register 4
+ * I(nphase)/Q(adrature) calibration register [5111+]
*/
-#define AR5K_PHY_IQ 0x9920 /* Register address */
+#define AR5K_PHY_IQ 0x9920 /* Register Address */
#define AR5K_PHY_IQ_CORR_Q_Q_COFF 0x0000001f /* Mask for q correction info */
#define AR5K_PHY_IQ_CORR_Q_I_COFF 0x000007e0 /* Mask for i correction info */
#define AR5K_PHY_IQ_CORR_Q_I_COFF_S 5
#define AR5K_PHY_IQ_CORR_ENABLE 0x00000800 /* Enable i/q correction */
-#define AR5K_PHY_IQ_CAL_NUM_LOG_MAX 0x0000f000
+#define AR5K_PHY_IQ_CAL_NUM_LOG_MAX 0x0000f000 /* Mask for max number of samples in log scale */
#define AR5K_PHY_IQ_CAL_NUM_LOG_MAX_S 12
#define AR5K_PHY_IQ_RUN 0x00010000 /* Run i/q calibration */
+#define AR5K_PHY_IQ_USE_PT_DF 0x00020000 /* Use pilot track df (?) */
+#define AR5K_PHY_IQ_EARLY_TRIG_THR 0x00200000 /* Early trigger threshold (?) (field) */
+#define AR5K_PHY_IQ_PILOT_MASK_EN 0x10000000 /* Enable pilot mask (?) */
+#define AR5K_PHY_IQ_CHAN_MASK_EN 0x20000000 /* Enable channel mask (?) */
+#define AR5K_PHY_IQ_SPUR_FILT_EN 0x40000000 /* Enable spur filter */
+#define AR5K_PHY_IQ_SPUR_RSSI_EN 0x80000000 /* Enable spur rssi */
+/*
+ * PHY timing register 5
+ * OFDM Self-correlator Cyclic RSSI threshold params
+ * (Check out bb_cycpwr_thr1 on ANI patent)
+ */
+#define AR5K_PHY_OFDM_SELFCORR 0x9924 /* Register Address */
+#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1_EN 0x00000001 /* Enable cyclic RSSI thr 1 */
+#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1 0x000000fe /* Mask for Cyclic RSSI threshold 1 */
+#define AR5K_PHY_OFDM_SELFCORR_CYPWR_THR3 0x00000100 /* Cyclic RSSI threshold 3 (field) (?) */
+#define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR_EN 0x00008000 /* Enable 1A RSSI threshold (?) */
+#define AR5K_PHY_OFDM_SELFCORR_RSSI_1ATHR 0x00010000 /* 1A RSSI threshold (field) (?) */
+#define AR5K_PHY_OFDM_SELFCORR_LSCTHR_HIRSSI 0x00800000 /* Long sc threshold hi rssi (?) */
+
+/*
+ * PHY-only warm reset register
+ */
+#define AR5K_PHY_WARM_RESET 0x9928
+
+/*
+ * PHY-only control register
+ */
+#define AR5K_PHY_CTL 0x992c /* Register Address */
+#define AR5K_PHY_CTL_RX_DRAIN_RATE 0x00000001 /* RX drain rate (?) */
+#define AR5K_PHY_CTL_LATE_TX_SIG_SYM 0x00000002 /* Late tx signal symbol (?) */
+#define AR5K_PHY_CTL_GEN_SCRAMBLER 0x00000004 /* Generate scrambler */
+#define AR5K_PHY_CTL_TX_ANT_SEL 0x00000008 /* TX antenna select */
+#define AR5K_PHY_CTL_TX_ANT_STATIC 0x00000010 /* Static TX antenna */
+#define AR5K_PHY_CTL_RX_ANT_SEL 0x00000020 /* RX antenna select */
+#define AR5K_PHY_CTL_RX_ANT_STATIC 0x00000040 /* Static RX antenna */
+#define AR5K_PHY_CTL_LOW_FREQ_SLE_EN 0x00000080 /* Enable low freq sleep */
/*
* PHY PAPD probe register [5111+ (?)]
@@ -1816,9 +2193,13 @@
* Because it's always 0 in 5211 initialization code
*/
#define AR5K_PHY_PAPD_PROBE 0x9930
+#define AR5K_PHY_PAPD_PROBE_SH_HI_PAR 0x00000001
+#define AR5K_PHY_PAPD_PROBE_PCDAC_BIAS 0x00000002
+#define AR5K_PHY_PAPD_PROBE_COMP_GAIN 0x00000040
#define AR5K_PHY_PAPD_PROBE_TXPOWER 0x00007e00
#define AR5K_PHY_PAPD_PROBE_TXPOWER_S 9
#define AR5K_PHY_PAPD_PROBE_TX_NEXT 0x00008000
+#define AR5K_PHY_PAPD_PROBE_PREDIST_EN 0x00010000
#define AR5K_PHY_PAPD_PROBE_TYPE 0x01800000 /* [5112+] */
#define AR5K_PHY_PAPD_PROBE_TYPE_S 23
#define AR5K_PHY_PAPD_PROBE_TYPE_OFDM 0
@@ -1848,15 +2229,16 @@
#define AR5K_PHY_FRAME_CTL (ah->ah_version == AR5K_AR5210 ? \
AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211)
/*---[5111+]---*/
-#define AR5K_PHY_FRAME_CTL_TX_CLIP 0x00000038
+#define AR5K_PHY_FRAME_CTL_TX_CLIP 0x00000038 /* Mask for tx clip (?) */
#define AR5K_PHY_FRAME_CTL_TX_CLIP_S 3
+#define AR5K_PHY_FRAME_CTL_PREP_CHINFO 0x00010000 /* Prepend chan info */
/*---[5110/5111]---*/
-#define AR5K_PHY_FRAME_CTL_TIMING_ERR 0x01000000
-#define AR5K_PHY_FRAME_CTL_PARITY_ERR 0x02000000
-#define AR5K_PHY_FRAME_CTL_ILLRATE_ERR 0x04000000 /* illegal rate */
-#define AR5K_PHY_FRAME_CTL_ILLLEN_ERR 0x08000000 /* illegal length */
+#define AR5K_PHY_FRAME_CTL_TIMING_ERR 0x01000000 /* PHY timing error */
+#define AR5K_PHY_FRAME_CTL_PARITY_ERR 0x02000000 /* Parity error */
+#define AR5K_PHY_FRAME_CTL_ILLRATE_ERR 0x04000000 /* Illegal rate */
+#define AR5K_PHY_FRAME_CTL_ILLLEN_ERR 0x08000000 /* Illegal length */
#define AR5K_PHY_FRAME_CTL_SERVICE_ERR 0x20000000
-#define AR5K_PHY_FRAME_CTL_TXURN_ERR 0x40000000 /* tx underrun */
+#define AR5K_PHY_FRAME_CTL_TXURN_ERR 0x40000000 /* TX underrun */
#define AR5K_PHY_FRAME_CTL_INI AR5K_PHY_FRAME_CTL_SERVICE_ERR | \
AR5K_PHY_FRAME_CTL_TXURN_ERR | \
AR5K_PHY_FRAME_CTL_ILLLEN_ERR | \
@@ -1915,6 +2297,11 @@ after DFS is enabled */
#define AR5K_PHY_ANT_SWITCH_TABLE_1 0x9964
/*
+ * PHY Noise floor threshold
+ */
+#define AR5K_PHY_NFTHRES 0x9968
+
+/*
* PHY clock sleep registers [5112+]
*/
#define AR5K_PHY_SCLOCK 0x99f0
@@ -1922,56 +2309,116 @@ after DFS is enabled */
#define AR5K_PHY_SDELAY 0x99f4
#define AR5K_PHY_SDELAY_32MHZ 0x000000ff
#define AR5K_PHY_SPENDING 0x99f8
+#define AR5K_PHY_SPENDING_14 0x00000014
+#define AR5K_PHY_SPENDING_18 0x00000018
#define AR5K_PHY_SPENDING_RF5111 0x00000018
-#define AR5K_PHY_SPENDING_RF5112 0x00000014 /* <- i 've only seen this on 2425 dumps ! */
-#define AR5K_PHY_SPENDING_RF5112A 0x0000000e /* but since i only have 5112A-based chips */
-#define AR5K_PHY_SPENDING_RF5424 0x00000012 /* to test it might be also for old 5112. */
+#define AR5K_PHY_SPENDING_RF5112 0x00000014
+/* #define AR5K_PHY_SPENDING_RF5112A 0x0000000e */
+/* #define AR5K_PHY_SPENDING_RF5424 0x00000012 */
+#define AR5K_PHY_SPENDING_RF5413 0x00000014
+#define AR5K_PHY_SPENDING_RF2413 0x00000014
+#define AR5K_PHY_SPENDING_RF2425 0x00000018
/*
* Misc PHY/radio registers [5110 - 5111]
*/
-#define AR5K_BB_GAIN_BASE 0x9b00 /* BaseBand Amplifier Gain table base address */
+#define AR5K_BB_GAIN_BASE 0x9b00 /* BaseBand Amplifier Gain table base address */
#define AR5K_BB_GAIN(_n) (AR5K_BB_GAIN_BASE + ((_n) << 2))
-#define AR5K_RF_GAIN_BASE 0x9a00 /* RF Amplrifier Gain table base address */
+#define AR5K_RF_GAIN_BASE 0x9a00 /* RF Amplrifier Gain table base address */
#define AR5K_RF_GAIN(_n) (AR5K_RF_GAIN_BASE + ((_n) << 2))
/*
* PHY timing IQ calibration result register [5111+]
*/
-#define AR5K_PHY_IQRES_CAL_PWR_I 0x9c10 /* I (Inphase) power value */
-#define AR5K_PHY_IQRES_CAL_PWR_Q 0x9c14 /* Q (Quadrature) power value */
+#define AR5K_PHY_IQRES_CAL_PWR_I 0x9c10 /* I (Inphase) power value */
+#define AR5K_PHY_IQRES_CAL_PWR_Q 0x9c14 /* Q (Quadrature) power value */
#define AR5K_PHY_IQRES_CAL_CORR 0x9c18 /* I/Q Correlation */
/*
* PHY current RSSI register [5111+]
*/
-#define AR5K_PHY_CURRENT_RSSI 0x9c1c
+#define AR5K_PHY_CURRENT_RSSI 0x9c1c
+
+/*
+ * PHY RF Bus grant register (?)
+ */
+#define AR5K_PHY_RFBUS_GRANT 0x9c20
+
+/*
+ * PHY ADC test register
+ */
+#define AR5K_PHY_ADC_TEST 0x9c24
+#define AR5K_PHY_ADC_TEST_I 0x00000001
+#define AR5K_PHY_ADC_TEST_Q 0x00000200
+
+/*
+ * PHY DAC test register
+ */
+#define AR5K_PHY_DAC_TEST 0x9c28
+#define AR5K_PHY_DAC_TEST_I 0x00000001
+#define AR5K_PHY_DAC_TEST_Q 0x00000200
+
+/*
+ * PHY PTAT register (?)
+ */
+#define AR5K_PHY_PTAT 0x9c2c
+
+/*
+ * PHY Illegal TX rate register [5112+]
+ */
+#define AR5K_PHY_BAD_TX_RATE 0x9c30
+
+/*
+ * PHY SPUR Power register [5112+]
+ */
+#define AR5K_PHY_SPUR_PWR 0x9c34 /* Register Address */
+#define AR5K_PHY_SPUR_PWR_I 0x00000001 /* SPUR Power estimate for I (field) */
+#define AR5K_PHY_SPUR_PWR_Q 0x00000100 /* SPUR Power estimate for Q (field) */
+#define AR5K_PHY_SPUR_PWR_FILT 0x00010000 /* Power with SPUR removed (field) */
+
+/*
+ * PHY Channel status register [5112+] (?)
+ */
+#define AR5K_PHY_CHAN_STATUS 0x9c38
+#define AR5K_PHY_CHAN_STATUS_BT_ACT 0x00000001
+#define AR5K_PHY_CHAN_STATUS_RX_CLR_RAW 0x00000002
+#define AR5K_PHY_CHAN_STATUS_RX_CLR_MAC 0x00000004
+#define AR5K_PHY_CHAN_STATUS_RX_CLR_PAP 0x00000008
+
+/*
+ * PHY PAPD I (power?) table (?)
+ * (92! entries)
+ */
+#define AR5K_PHY_PAPD_I_BASE 0xa000
+#define AR5K_PHY_PAPD_I(_n) (AR5K_PHY_PAPD_I_BASE + ((_n) << 2))
/*
* PHY PCDAC TX power table
*/
#define AR5K_PHY_PCDAC_TXPOWER_BASE_5211 0xa180
-#define AR5K_PHY_PCDAC_TXPOWER_BASE_5413 0xa280
-#define AR5K_PHY_PCDAC_TXPOWER_BASE (ah->ah_radio >= AR5K_RF5413 ? \
- AR5K_PHY_PCDAC_TXPOWER_BASE_5413 :\
+#define AR5K_PHY_PCDAC_TXPOWER_BASE_2413 0xa280
+#define AR5K_PHY_PCDAC_TXPOWER_BASE (ah->ah_radio >= AR5K_RF2413 ? \
+ AR5K_PHY_PCDAC_TXPOWER_BASE_2413 :\
AR5K_PHY_PCDAC_TXPOWER_BASE_5211)
#define AR5K_PHY_PCDAC_TXPOWER(_n) (AR5K_PHY_PCDAC_TXPOWER_BASE + ((_n) << 2))
/*
* PHY mode register [5111+]
*/
-#define AR5K_PHY_MODE 0x0a200 /* Register address */
-#define AR5K_PHY_MODE_MOD 0x00000001 /* PHY Modulation mask*/
+#define AR5K_PHY_MODE 0x0a200 /* Register Address */
+#define AR5K_PHY_MODE_MOD 0x00000001 /* PHY Modulation bit */
#define AR5K_PHY_MODE_MOD_OFDM 0
#define AR5K_PHY_MODE_MOD_CCK 1
-#define AR5K_PHY_MODE_FREQ 0x00000002 /* Freq mode mask */
+#define AR5K_PHY_MODE_FREQ 0x00000002 /* Freq mode bit */
#define AR5K_PHY_MODE_FREQ_5GHZ 0
#define AR5K_PHY_MODE_FREQ_2GHZ 2
-#define AR5K_PHY_MODE_MOD_DYN 0x00000004 /* Dynamic OFDM/CCK mode mask [5112+] */
+#define AR5K_PHY_MODE_MOD_DYN 0x00000004 /* Enable Dynamic OFDM/CCK mode [5112+] */
#define AR5K_PHY_MODE_RAD 0x00000008 /* [5212+] */
#define AR5K_PHY_MODE_RAD_RF5111 0
#define AR5K_PHY_MODE_RAD_RF5112 8
-#define AR5K_PHY_MODE_XR 0x00000010 /* [5112+] */
+#define AR5K_PHY_MODE_XR 0x00000010 /* Enable XR mode [5112+] */
+#define AR5K_PHY_MODE_HALF_RATE 0x00000020 /* Enable Half rate (test) */
+#define AR5K_PHY_MODE_QUARTER_RATE 0x00000040 /* Enable Quarter rat (test) */
/*
* PHY CCK transmit control register [5111+ (?)]
@@ -1979,6 +2426,15 @@ after DFS is enabled */
#define AR5K_PHY_CCKTXCTL 0xa204
#define AR5K_PHY_CCKTXCTL_WORLD 0x00000000
#define AR5K_PHY_CCKTXCTL_JAPAN 0x00000010
+#define AR5K_PHY_CCKTXCTL_SCRAMBLER_DIS 0x00000001
+#define AR5K_PHY_CCKTXCTK_DAC_SCALE 0x00000004
+
+/*
+ * PHY CCK Cross-correlator Barker RSSI threshold register [5212+]
+ */
+#define AR5K_PHY_CCK_CROSSCORR 0xa208
+#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR 0x0000000f
+#define AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR_S 0
/*
* PHY 2GHz gain register [5111+]
diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig
new file mode 100644
index 00000000000..9e19dcceb3a
--- /dev/null
+++ b/drivers/net/wireless/ath9k/Kconfig
@@ -0,0 +1,8 @@
+config ATH9K
+ tristate "Atheros 802.11n wireless cards support"
+ depends on PCI && MAC80211 && WLAN_80211
+ ---help---
+ This module adds support for wireless adapters based on
+ Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets.
+
+ If you choose to build a module, it'll be called ath9k.
diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile
new file mode 100644
index 00000000000..a6411517e5f
--- /dev/null
+++ b/drivers/net/wireless/ath9k/Makefile
@@ -0,0 +1,11 @@
+ath9k-y += hw.o \
+ phy.o \
+ regd.o \
+ beacon.o \
+ main.o \
+ recv.o \
+ xmit.o \
+ rc.o \
+ core.o
+
+obj-$(CONFIG_ATH9K) += ath9k.o
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
new file mode 100644
index 00000000000..d1b0fbae5a3
--- /dev/null
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ATH9K_H
+#define ATH9K_H
+
+#include <linux/io.h>
+
+#define ATHEROS_VENDOR_ID 0x168c
+
+#define AR5416_DEVID_PCI 0x0023
+#define AR5416_DEVID_PCIE 0x0024
+#define AR9160_DEVID_PCI 0x0027
+#define AR9280_DEVID_PCI 0x0029
+#define AR9280_DEVID_PCIE 0x002a
+
+#define AR5416_AR9100_DEVID 0x000b
+
+#define AR_SUBVENDOR_ID_NOG 0x0e11
+#define AR_SUBVENDOR_ID_NEW_A 0x7065
+
+#define ATH9K_TXERR_XRETRY 0x01
+#define ATH9K_TXERR_FILT 0x02
+#define ATH9K_TXERR_FIFO 0x04
+#define ATH9K_TXERR_XTXOP 0x08
+#define ATH9K_TXERR_TIMER_EXPIRED 0x10
+
+#define ATH9K_TX_BA 0x01
+#define ATH9K_TX_PWRMGMT 0x02
+#define ATH9K_TX_DESC_CFG_ERR 0x04
+#define ATH9K_TX_DATA_UNDERRUN 0x08
+#define ATH9K_TX_DELIM_UNDERRUN 0x10
+#define ATH9K_TX_SW_ABORTED 0x40
+#define ATH9K_TX_SW_FILTERED 0x80
+
+#define NBBY 8
+
+struct ath_tx_status {
+ u32 ts_tstamp;
+ u16 ts_seqnum;
+ u8 ts_status;
+ u8 ts_ratecode;
+ u8 ts_rateindex;
+ int8_t ts_rssi;
+ u8 ts_shortretry;
+ u8 ts_longretry;
+ u8 ts_virtcol;
+ u8 ts_antenna;
+ u8 ts_flags;
+ int8_t ts_rssi_ctl0;
+ int8_t ts_rssi_ctl1;
+ int8_t ts_rssi_ctl2;
+ int8_t ts_rssi_ext0;
+ int8_t ts_rssi_ext1;
+ int8_t ts_rssi_ext2;
+ u8 pad[3];
+ u32 ba_low;
+ u32 ba_high;
+ u32 evm0;
+ u32 evm1;
+ u32 evm2;
+};
+
+struct ath_rx_status {
+ u32 rs_tstamp;
+ u16 rs_datalen;
+ u8 rs_status;
+ u8 rs_phyerr;
+ int8_t rs_rssi;
+ u8 rs_keyix;
+ u8 rs_rate;
+ u8 rs_antenna;
+ u8 rs_more;
+ int8_t rs_rssi_ctl0;
+ int8_t rs_rssi_ctl1;
+ int8_t rs_rssi_ctl2;
+ int8_t rs_rssi_ext0;
+ int8_t rs_rssi_ext1;
+ int8_t rs_rssi_ext2;
+ u8 rs_isaggr;
+ u8 rs_moreaggr;
+ u8 rs_num_delims;
+ u8 rs_flags;
+ u32 evm0;
+ u32 evm1;
+ u32 evm2;
+};
+
+#define ATH9K_RXERR_CRC 0x01
+#define ATH9K_RXERR_PHY 0x02
+#define ATH9K_RXERR_FIFO 0x04
+#define ATH9K_RXERR_DECRYPT 0x08
+#define ATH9K_RXERR_MIC 0x10
+
+#define ATH9K_RX_MORE 0x01
+#define ATH9K_RX_MORE_AGGR 0x02
+#define ATH9K_RX_GI 0x04
+#define ATH9K_RX_2040 0x08
+#define ATH9K_RX_DELIM_CRC_PRE 0x10
+#define ATH9K_RX_DELIM_CRC_POST 0x20
+#define ATH9K_RX_DECRYPT_BUSY 0x40
+
+#define ATH9K_RXKEYIX_INVALID ((u8)-1)
+#define ATH9K_TXKEYIX_INVALID ((u32)-1)
+
+struct ath_desc {
+ u32 ds_link;
+ u32 ds_data;
+ u32 ds_ctl0;
+ u32 ds_ctl1;
+ u32 ds_hw[20];
+ union {
+ struct ath_tx_status tx;
+ struct ath_rx_status rx;
+ void *stats;
+ } ds_us;
+ void *ds_vdata;
+} __packed;
+
+#define ds_txstat ds_us.tx
+#define ds_rxstat ds_us.rx
+#define ds_stat ds_us.stats
+
+#define ATH9K_TXDESC_CLRDMASK 0x0001
+#define ATH9K_TXDESC_NOACK 0x0002
+#define ATH9K_TXDESC_RTSENA 0x0004
+#define ATH9K_TXDESC_CTSENA 0x0008
+#define ATH9K_TXDESC_INTREQ 0x0010
+#define ATH9K_TXDESC_VEOL 0x0020
+#define ATH9K_TXDESC_EXT_ONLY 0x0040
+#define ATH9K_TXDESC_EXT_AND_CTL 0x0080
+#define ATH9K_TXDESC_VMF 0x0100
+#define ATH9K_TXDESC_FRAG_IS_ON 0x0200
+
+#define ATH9K_RXDESC_INTREQ 0x0020
+
+enum wireless_mode {
+ ATH9K_MODE_11A = 0,
+ ATH9K_MODE_11B = 2,
+ ATH9K_MODE_11G = 3,
+ ATH9K_MODE_11NA_HT20 = 6,
+ ATH9K_MODE_11NG_HT20 = 7,
+ ATH9K_MODE_11NA_HT40PLUS = 8,
+ ATH9K_MODE_11NA_HT40MINUS = 9,
+ ATH9K_MODE_11NG_HT40PLUS = 10,
+ ATH9K_MODE_11NG_HT40MINUS = 11,
+ ATH9K_MODE_MAX
+};
+
+enum ath9k_hw_caps {
+ ATH9K_HW_CAP_CHAN_SPREAD = BIT(0),
+ ATH9K_HW_CAP_MIC_AESCCM = BIT(1),
+ ATH9K_HW_CAP_MIC_CKIP = BIT(2),
+ ATH9K_HW_CAP_MIC_TKIP = BIT(3),
+ ATH9K_HW_CAP_CIPHER_AESCCM = BIT(4),
+ ATH9K_HW_CAP_CIPHER_CKIP = BIT(5),
+ ATH9K_HW_CAP_CIPHER_TKIP = BIT(6),
+ ATH9K_HW_CAP_VEOL = BIT(7),
+ ATH9K_HW_CAP_BSSIDMASK = BIT(8),
+ ATH9K_HW_CAP_MCAST_KEYSEARCH = BIT(9),
+ ATH9K_HW_CAP_CHAN_HALFRATE = BIT(10),
+ ATH9K_HW_CAP_CHAN_QUARTERRATE = BIT(11),
+ ATH9K_HW_CAP_HT = BIT(12),
+ ATH9K_HW_CAP_GTT = BIT(13),
+ ATH9K_HW_CAP_FASTCC = BIT(14),
+ ATH9K_HW_CAP_RFSILENT = BIT(15),
+ ATH9K_HW_CAP_WOW = BIT(16),
+ ATH9K_HW_CAP_CST = BIT(17),
+ ATH9K_HW_CAP_ENHANCEDPM = BIT(18),
+ ATH9K_HW_CAP_AUTOSLEEP = BIT(19),
+ ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(20),
+ ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT = BIT(21),
+};
+
+enum ath9k_capability_type {
+ ATH9K_CAP_CIPHER = 0,
+ ATH9K_CAP_TKIP_MIC,
+ ATH9K_CAP_TKIP_SPLIT,
+ ATH9K_CAP_PHYCOUNTERS,
+ ATH9K_CAP_DIVERSITY,
+ ATH9K_CAP_TXPOW,
+ ATH9K_CAP_PHYDIAG,
+ ATH9K_CAP_MCAST_KEYSRCH,
+ ATH9K_CAP_TSF_ADJUST,
+ ATH9K_CAP_WME_TKIPMIC,
+ ATH9K_CAP_RFSILENT,
+ ATH9K_CAP_ANT_CFG_2GHZ,
+ ATH9K_CAP_ANT_CFG_5GHZ
+};
+
+struct ath9k_hw_capabilities {
+ u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
+ DECLARE_BITMAP(wireless_modes, ATH9K_MODE_MAX); /* ATH9K_MODE_* */
+ u16 total_queues;
+ u16 keycache_size;
+ u16 low_5ghz_chan, high_5ghz_chan;
+ u16 low_2ghz_chan, high_2ghz_chan;
+ u16 num_mr_retries;
+ u16 rts_aggr_limit;
+ u8 tx_chainmask;
+ u8 rx_chainmask;
+ u16 tx_triglevel_max;
+ u16 reg_cap;
+ u8 num_gpio_pins;
+ u8 num_antcfg_2ghz;
+ u8 num_antcfg_5ghz;
+};
+
+struct ath9k_ops_config {
+ int dma_beacon_response_time;
+ int sw_beacon_response_time;
+ int additional_swba_backoff;
+ int ack_6mb;
+ int cwm_ignore_extcca;
+ u8 pcie_powersave_enable;
+ u8 pcie_l1skp_enable;
+ u8 pcie_clock_req;
+ u32 pcie_waen;
+ int pcie_power_reset;
+ u8 pcie_restore;
+ u8 analog_shiftreg;
+ u8 ht_enable;
+ u32 ofdm_trig_low;
+ u32 ofdm_trig_high;
+ u32 cck_trig_high;
+ u32 cck_trig_low;
+ u32 enable_ani;
+ u8 noise_immunity_level;
+ u32 ofdm_weaksignal_det;
+ u32 cck_weaksignal_thr;
+ u8 spur_immunity_level;
+ u8 firstep_level;
+ int8_t rssi_thr_high;
+ int8_t rssi_thr_low;
+ u16 diversity_control;
+ u16 antenna_switch_swap;
+ int serialize_regmode;
+ int intr_mitigation;
+#define SPUR_DISABLE 0
+#define SPUR_ENABLE_IOCTL 1
+#define SPUR_ENABLE_EEPROM 2
+#define AR_EEPROM_MODAL_SPURS 5
+#define AR_SPUR_5413_1 1640
+#define AR_SPUR_5413_2 1200
+#define AR_NO_SPUR 0x8000
+#define AR_BASE_FREQ_2GHZ 2300
+#define AR_BASE_FREQ_5GHZ 4900
+#define AR_SPUR_FEEQ_BOUND_HT40 19
+#define AR_SPUR_FEEQ_BOUND_HT20 10
+ int spurmode;
+ u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
+};
+
+enum ath9k_tx_queue {
+ ATH9K_TX_QUEUE_INACTIVE = 0,
+ ATH9K_TX_QUEUE_DATA,
+ ATH9K_TX_QUEUE_BEACON,
+ ATH9K_TX_QUEUE_CAB,
+ ATH9K_TX_QUEUE_UAPSD,
+ ATH9K_TX_QUEUE_PSPOLL
+};
+
+#define ATH9K_NUM_TX_QUEUES 10
+
+enum ath9k_tx_queue_subtype {
+ ATH9K_WME_AC_BK = 0,
+ ATH9K_WME_AC_BE,
+ ATH9K_WME_AC_VI,
+ ATH9K_WME_AC_VO,
+ ATH9K_WME_UPSD
+};
+
+enum ath9k_tx_queue_flags {
+ TXQ_FLAG_TXOKINT_ENABLE = 0x0001,
+ TXQ_FLAG_TXERRINT_ENABLE = 0x0001,
+ TXQ_FLAG_TXDESCINT_ENABLE = 0x0002,
+ TXQ_FLAG_TXEOLINT_ENABLE = 0x0004,
+ TXQ_FLAG_TXURNINT_ENABLE = 0x0008,
+ TXQ_FLAG_BACKOFF_DISABLE = 0x0010,
+ TXQ_FLAG_COMPRESSION_ENABLE = 0x0020,
+ TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE = 0x0040,
+ TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE = 0x0080,
+};
+
+#define ATH9K_TXQ_USEDEFAULT ((u32) -1)
+
+#define ATH9K_DECOMP_MASK_SIZE 128
+#define ATH9K_READY_TIME_LO_BOUND 50
+#define ATH9K_READY_TIME_HI_BOUND 96
+
+enum ath9k_pkt_type {
+ ATH9K_PKT_TYPE_NORMAL = 0,
+ ATH9K_PKT_TYPE_ATIM,
+ ATH9K_PKT_TYPE_PSPOLL,
+ ATH9K_PKT_TYPE_BEACON,
+ ATH9K_PKT_TYPE_PROBE_RESP,
+ ATH9K_PKT_TYPE_CHIRP,
+ ATH9K_PKT_TYPE_GRP_POLL,
+};
+
+struct ath9k_tx_queue_info {
+ u32 tqi_ver;
+ enum ath9k_tx_queue tqi_type;
+ enum ath9k_tx_queue_subtype tqi_subtype;
+ enum ath9k_tx_queue_flags tqi_qflags;
+ u32 tqi_priority;
+ u32 tqi_aifs;
+ u32 tqi_cwmin;
+ u32 tqi_cwmax;
+ u16 tqi_shretry;
+ u16 tqi_lgretry;
+ u32 tqi_cbrPeriod;
+ u32 tqi_cbrOverflowLimit;
+ u32 tqi_burstTime;
+ u32 tqi_readyTime;
+ u32 tqi_physCompBuf;
+ u32 tqi_intFlags;
+};
+
+enum ath9k_rx_filter {
+ ATH9K_RX_FILTER_UCAST = 0x00000001,
+ ATH9K_RX_FILTER_MCAST = 0x00000002,
+ ATH9K_RX_FILTER_BCAST = 0x00000004,
+ ATH9K_RX_FILTER_CONTROL = 0x00000008,
+ ATH9K_RX_FILTER_BEACON = 0x00000010,
+ ATH9K_RX_FILTER_PROM = 0x00000020,
+ ATH9K_RX_FILTER_PROBEREQ = 0x00000080,
+ ATH9K_RX_FILTER_PSPOLL = 0x00004000,
+ ATH9K_RX_FILTER_PHYERR = 0x00000100,
+ ATH9K_RX_FILTER_PHYRADAR = 0x00002000,
+};
+
+enum ath9k_int {
+ ATH9K_INT_RX = 0x00000001,
+ ATH9K_INT_RXDESC = 0x00000002,
+ ATH9K_INT_RXNOFRM = 0x00000008,
+ ATH9K_INT_RXEOL = 0x00000010,
+ ATH9K_INT_RXORN = 0x00000020,
+ ATH9K_INT_TX = 0x00000040,
+ ATH9K_INT_TXDESC = 0x00000080,
+ ATH9K_INT_TIM_TIMER = 0x00000100,
+ ATH9K_INT_TXURN = 0x00000800,
+ ATH9K_INT_MIB = 0x00001000,
+ ATH9K_INT_RXPHY = 0x00004000,
+ ATH9K_INT_RXKCM = 0x00008000,
+ ATH9K_INT_SWBA = 0x00010000,
+ ATH9K_INT_BMISS = 0x00040000,
+ ATH9K_INT_BNR = 0x00100000,
+ ATH9K_INT_TIM = 0x00200000,
+ ATH9K_INT_DTIM = 0x00400000,
+ ATH9K_INT_DTIMSYNC = 0x00800000,
+ ATH9K_INT_GPIO = 0x01000000,
+ ATH9K_INT_CABEND = 0x02000000,
+ ATH9K_INT_CST = 0x10000000,
+ ATH9K_INT_GTT = 0x20000000,
+ ATH9K_INT_FATAL = 0x40000000,
+ ATH9K_INT_GLOBAL = 0x80000000,
+ ATH9K_INT_BMISC = ATH9K_INT_TIM |
+ ATH9K_INT_DTIM |
+ ATH9K_INT_DTIMSYNC |
+ ATH9K_INT_CABEND,
+ ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM |
+ ATH9K_INT_RXDESC |
+ ATH9K_INT_RXEOL |
+ ATH9K_INT_RXORN |
+ ATH9K_INT_TXURN |
+ ATH9K_INT_TXDESC |
+ ATH9K_INT_MIB |
+ ATH9K_INT_RXPHY |
+ ATH9K_INT_RXKCM |
+ ATH9K_INT_SWBA |
+ ATH9K_INT_BMISS |
+ ATH9K_INT_GPIO,
+ ATH9K_INT_NOCARD = 0xffffffff
+};
+
+struct ath9k_rate_table {
+ int rateCount;
+ u8 rateCodeToIndex[256];
+ struct {
+ u8 valid;
+ u8 phy;
+ u32 rateKbps;
+ u8 rateCode;
+ u8 shortPreamble;
+ u8 dot11Rate;
+ u8 controlRate;
+ u16 lpAckDuration;
+ u16 spAckDuration;
+ } info[32];
+};
+
+#define ATH9K_RATESERIES_RTS_CTS 0x0001
+#define ATH9K_RATESERIES_2040 0x0002
+#define ATH9K_RATESERIES_HALFGI 0x0004
+
+struct ath9k_11n_rate_series {
+ u32 Tries;
+ u32 Rate;
+ u32 PktDuration;
+ u32 ChSel;
+ u32 RateFlags;
+};
+
+#define CHANNEL_CW_INT 0x00002
+#define CHANNEL_CCK 0x00020
+#define CHANNEL_OFDM 0x00040
+#define CHANNEL_2GHZ 0x00080
+#define CHANNEL_5GHZ 0x00100
+#define CHANNEL_PASSIVE 0x00200
+#define CHANNEL_DYN 0x00400
+#define CHANNEL_HALF 0x04000
+#define CHANNEL_QUARTER 0x08000
+#define CHANNEL_HT20 0x10000
+#define CHANNEL_HT40PLUS 0x20000
+#define CHANNEL_HT40MINUS 0x40000
+
+#define CHANNEL_INTERFERENCE 0x01
+#define CHANNEL_DFS 0x02
+#define CHANNEL_4MS_LIMIT 0x04
+#define CHANNEL_DFS_CLEAR 0x08
+#define CHANNEL_DISALLOW_ADHOC 0x10
+#define CHANNEL_PER_11D_ADHOC 0x20
+
+#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM)
+#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK)
+#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM)
+#define CHANNEL_G_HT20 (CHANNEL_2GHZ|CHANNEL_HT20)
+#define CHANNEL_A_HT20 (CHANNEL_5GHZ|CHANNEL_HT20)
+#define CHANNEL_G_HT40PLUS (CHANNEL_2GHZ|CHANNEL_HT40PLUS)
+#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS)
+#define CHANNEL_A_HT40PLUS (CHANNEL_5GHZ|CHANNEL_HT40PLUS)
+#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS)
+#define CHANNEL_ALL \
+ (CHANNEL_OFDM| \
+ CHANNEL_CCK| \
+ CHANNEL_2GHZ | \
+ CHANNEL_5GHZ | \
+ CHANNEL_HT20 | \
+ CHANNEL_HT40PLUS | \
+ CHANNEL_HT40MINUS)
+
+struct ath9k_channel {
+ u16 channel;
+ u32 channelFlags;
+ u8 privFlags;
+ int8_t maxRegTxPower;
+ int8_t maxTxPower;
+ int8_t minTxPower;
+ u32 chanmode;
+ int32_t CalValid;
+ bool oneTimeCalsDone;
+ int8_t iCoff;
+ int8_t qCoff;
+ int16_t rawNoiseFloor;
+ int8_t antennaMax;
+ u32 regDmnFlags;
+ u32 conformanceTestLimit[3]; /* 0:11a, 1: 11b, 2:11g */
+#ifdef ATH_NF_PER_CHAN
+ struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+#endif
+};
+
+#define IS_CHAN_A(_c) ((((_c)->channelFlags & CHANNEL_A) == CHANNEL_A) || \
+ (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \
+ (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \
+ (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS))
+#define IS_CHAN_B(_c) (((_c)->channelFlags & CHANNEL_B) == CHANNEL_B)
+#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
+ (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
+ (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
+ (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS))
+#define IS_CHAN_CCK(_c) (((_c)->channelFlags & CHANNEL_CCK) != 0)
+#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
+#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
+#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
+#define IS_CHAN_PASSIVE(_c) (((_c)->channelFlags & CHANNEL_PASSIVE) != 0)
+#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0)
+#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
+
+/* These macros check chanmode and not channelFlags */
+#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) || \
+ ((_c)->chanmode == CHANNEL_G_HT20))
+#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \
+ ((_c)->chanmode == CHANNEL_A_HT40MINUS) || \
+ ((_c)->chanmode == CHANNEL_G_HT40PLUS) || \
+ ((_c)->chanmode == CHANNEL_G_HT40MINUS))
+#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c)))
+
+#define IS_CHAN_IN_PUBLIC_SAFETY_BAND(_c) ((_c) > 4940 && (_c) < 4990)
+#define IS_CHAN_A_5MHZ_SPACED(_c) \
+ ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) && \
+ (((_c)->channel % 20) != 0) && \
+ (((_c)->channel % 10) != 0))
+
+struct ath9k_keyval {
+ u8 kv_type;
+ u8 kv_pad;
+ u16 kv_len;
+ u8 kv_val[16];
+ u8 kv_mic[8];
+ u8 kv_txmic[8];
+};
+
+enum ath9k_key_type {
+ ATH9K_KEY_TYPE_CLEAR,
+ ATH9K_KEY_TYPE_WEP,
+ ATH9K_KEY_TYPE_AES,
+ ATH9K_KEY_TYPE_TKIP,
+};
+
+enum ath9k_cipher {
+ ATH9K_CIPHER_WEP = 0,
+ ATH9K_CIPHER_AES_OCB = 1,
+ ATH9K_CIPHER_AES_CCM = 2,
+ ATH9K_CIPHER_CKIP = 3,
+ ATH9K_CIPHER_TKIP = 4,
+ ATH9K_CIPHER_CLR = 5,
+ ATH9K_CIPHER_MIC = 127
+};
+
+#define AR_EEPROM_EEPCAP_COMPRESS_DIS 0x0001
+#define AR_EEPROM_EEPCAP_AES_DIS 0x0002
+#define AR_EEPROM_EEPCAP_FASTFRAME_DIS 0x0004
+#define AR_EEPROM_EEPCAP_BURST_DIS 0x0008
+#define AR_EEPROM_EEPCAP_MAXQCU 0x01F0
+#define AR_EEPROM_EEPCAP_MAXQCU_S 4
+#define AR_EEPROM_EEPCAP_HEAVY_CLIP_EN 0x0200
+#define AR_EEPROM_EEPCAP_KC_ENTRIES 0xF000
+#define AR_EEPROM_EEPCAP_KC_ENTRIES_S 12
+
+#define AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND 0x0040
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN 0x0080
+#define AR_EEPROM_EEREGCAP_EN_KK_U2 0x0100
+#define AR_EEPROM_EEREGCAP_EN_KK_MIDBAND 0x0200
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD 0x0400
+#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A 0x0800
+
+#define AR_EEPROM_EEREGCAP_EN_KK_U1_ODD_PRE4_0 0x4000
+#define AR_EEPROM_EEREGCAP_EN_KK_NEW_11A_PRE4_0 0x8000
+
+#define SD_NO_CTL 0xE0
+#define NO_CTL 0xff
+#define CTL_MODE_M 7
+#define CTL_11A 0
+#define CTL_11B 1
+#define CTL_11G 2
+#define CTL_2GHT20 5
+#define CTL_5GHT20 6
+#define CTL_2GHT40 7
+#define CTL_5GHT40 8
+
+#define AR_EEPROM_MAC(i) (0x1d+(i))
+#define EEP_SCALE 100
+#define EEP_DELTA 10
+
+#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c
+#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2
+#define AR_EEPROM_RFSILENT_POLARITY 0x0002
+#define AR_EEPROM_RFSILENT_POLARITY_S 1
+
+#define CTRY_DEBUG 0x1ff
+#define CTRY_DEFAULT 0
+
+enum reg_ext_bitmap {
+ REG_EXT_JAPAN_MIDBAND = 1,
+ REG_EXT_FCC_DFS_HT40 = 2,
+ REG_EXT_JAPAN_NONDFS_HT40 = 3,
+ REG_EXT_JAPAN_DFS_HT40 = 4
+};
+
+struct ath9k_country_entry {
+ u16 countryCode;
+ u16 regDmnEnum;
+ u16 regDmn5G;
+ u16 regDmn2G;
+ u8 isMultidomain;
+ u8 iso[3];
+};
+
+#define REG_WRITE(_ah, _reg, _val) iowrite32(_val, _ah->ah_sh + _reg)
+#define REG_READ(_ah, _reg) ioread32(_ah->ah_sh + _reg)
+
+#define SM(_v, _f) (((_v) << _f##_S) & _f)
+#define MS(_v, _f) (((_v) & _f) >> _f##_S)
+#define REG_RMW(_a, _r, _set, _clr) \
+ REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set))
+#define REG_RMW_FIELD(_a, _r, _f, _v) \
+ REG_WRITE(_a, _r, \
+ (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f))
+#define REG_SET_BIT(_a, _r, _f) \
+ REG_WRITE(_a, _r, REG_READ(_a, _r) | _f)
+#define REG_CLR_BIT(_a, _r, _f) \
+ REG_WRITE(_a, _r, REG_READ(_a, _r) & ~_f)
+
+#define ATH9K_COMP_BUF_MAX_SIZE 9216
+#define ATH9K_COMP_BUF_ALIGN_SIZE 512
+
+#define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001
+
+#define INIT_AIFS 2
+#define INIT_CWMIN 15
+#define INIT_CWMIN_11B 31
+#define INIT_CWMAX 1023
+#define INIT_SH_RETRY 10
+#define INIT_LG_RETRY 10
+#define INIT_SSH_RETRY 32
+#define INIT_SLG_RETRY 32
+
+#define WLAN_CTRL_FRAME_SIZE (2+2+6+4)
+
+#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1)
+#define ATH_AMPDU_LIMIT_DEFAULT ATH_AMPDU_LIMIT_MAX
+
+#define IEEE80211_WEP_IVLEN 3
+#define IEEE80211_WEP_KIDLEN 1
+#define IEEE80211_WEP_CRCLEN 4
+#define IEEE80211_MAX_MPDU_LEN (3840 + FCS_LEN + \
+ (IEEE80211_WEP_IVLEN + \
+ IEEE80211_WEP_KIDLEN + \
+ IEEE80211_WEP_CRCLEN))
+#define IEEE80211_MAX_LEN (2300 + FCS_LEN + \
+ (IEEE80211_WEP_IVLEN + \
+ IEEE80211_WEP_KIDLEN + \
+ IEEE80211_WEP_CRCLEN))
+
+#define MAX_REG_ADD_COUNT 129
+#define MAX_RATE_POWER 63
+
+enum ath9k_power_mode {
+ ATH9K_PM_AWAKE = 0,
+ ATH9K_PM_FULL_SLEEP,
+ ATH9K_PM_NETWORK_SLEEP,
+ ATH9K_PM_UNDEFINED
+};
+
+struct ath9k_mib_stats {
+ u32 ackrcv_bad;
+ u32 rts_bad;
+ u32 rts_good;
+ u32 fcs_bad;
+ u32 beacons;
+};
+
+enum ath9k_ant_setting {
+ ATH9K_ANT_VARIABLE = 0,
+ ATH9K_ANT_FIXED_A,
+ ATH9K_ANT_FIXED_B
+};
+
+enum ath9k_opmode {
+ ATH9K_M_STA = 1,
+ ATH9K_M_IBSS = 0,
+ ATH9K_M_HOSTAP = 6,
+ ATH9K_M_MONITOR = 8
+};
+
+#define ATH9K_SLOT_TIME_6 6
+#define ATH9K_SLOT_TIME_9 9
+#define ATH9K_SLOT_TIME_20 20
+
+enum ath9k_ht_macmode {
+ ATH9K_HT_MACMODE_20 = 0,
+ ATH9K_HT_MACMODE_2040 = 1,
+};
+
+enum ath9k_ht_extprotspacing {
+ ATH9K_HT_EXTPROTSPACING_20 = 0,
+ ATH9K_HT_EXTPROTSPACING_25 = 1,
+};
+
+struct ath9k_ht_cwm {
+ enum ath9k_ht_macmode ht_macmode;
+ enum ath9k_ht_extprotspacing ht_extprotspacing;
+};
+
+enum ath9k_ani_cmd {
+ ATH9K_ANI_PRESENT = 0x1,
+ ATH9K_ANI_NOISE_IMMUNITY_LEVEL = 0x2,
+ ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION = 0x4,
+ ATH9K_ANI_CCK_WEAK_SIGNAL_THR = 0x8,
+ ATH9K_ANI_FIRSTEP_LEVEL = 0x10,
+ ATH9K_ANI_SPUR_IMMUNITY_LEVEL = 0x20,
+ ATH9K_ANI_MODE = 0x40,
+ ATH9K_ANI_PHYERR_RESET = 0x80,
+ ATH9K_ANI_ALL = 0xff
+};
+
+enum phytype {
+ PHY_DS,
+ PHY_FH,
+ PHY_OFDM,
+ PHY_HT,
+};
+#define PHY_CCK PHY_DS
+
+enum start_adhoc_option {
+ START_ADHOC_NO_11A,
+ START_ADHOC_PER_11D,
+ START_ADHOC_IN_11A,
+ START_ADHOC_IN_11B,
+};
+
+enum ath9k_tp_scale {
+ ATH9K_TP_SCALE_MAX = 0,
+ ATH9K_TP_SCALE_50,
+ ATH9K_TP_SCALE_25,
+ ATH9K_TP_SCALE_12,
+ ATH9K_TP_SCALE_MIN
+};
+
+enum ser_reg_mode {
+ SER_REG_MODE_OFF = 0,
+ SER_REG_MODE_ON = 1,
+ SER_REG_MODE_AUTO = 2,
+};
+
+#define AR_PHY_CCA_MAX_GOOD_VALUE -85
+#define AR_PHY_CCA_MAX_HIGH_VALUE -62
+#define AR_PHY_CCA_MIN_BAD_VALUE -121
+#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3
+#define AR_PHY_CCA_FILTERWINDOW_LENGTH 5
+
+#define ATH9K_NF_CAL_HIST_MAX 5
+#define NUM_NF_READINGS 6
+
+struct ath9k_nfcal_hist {
+ int16_t nfCalBuffer[ATH9K_NF_CAL_HIST_MAX];
+ u8 currIndex;
+ int16_t privNF;
+ u8 invalidNFcount;
+};
+
+struct ath9k_beacon_state {
+ u32 bs_nexttbtt;
+ u32 bs_nextdtim;
+ u32 bs_intval;
+#define ATH9K_BEACON_PERIOD 0x0000ffff
+#define ATH9K_BEACON_ENA 0x00800000
+#define ATH9K_BEACON_RESET_TSF 0x01000000
+ u32 bs_dtimperiod;
+ u16 bs_cfpperiod;
+ u16 bs_cfpmaxduration;
+ u32 bs_cfpnext;
+ u16 bs_timoffset;
+ u16 bs_bmissthreshold;
+ u32 bs_sleepduration;
+};
+
+struct ath9k_node_stats {
+ u32 ns_avgbrssi;
+ u32 ns_avgrssi;
+ u32 ns_avgtxrssi;
+ u32 ns_avgtxrate;
+};
+
+#define ATH9K_RSSI_EP_MULTIPLIER (1<<7)
+
+enum ath9k_gpio_output_mux_type {
+ ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT,
+ ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED,
+ ATH9K_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED,
+ ATH9K_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED,
+ ATH9K_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED,
+ ATH9K_GPIO_OUTPUT_MUX_NUM_ENTRIES
+};
+
+enum {
+ ATH9K_RESET_POWER_ON,
+ ATH9K_RESET_WARM,
+ ATH9K_RESET_COLD,
+};
+
+#define AH_USE_EEPROM 0x1
+
+struct ath_hal {
+ u32 ah_magic;
+ u16 ah_devid;
+ u16 ah_subvendorid;
+ struct ath_softc *ah_sc;
+ void __iomem *ah_sh;
+ u16 ah_countryCode;
+ u32 ah_macVersion;
+ u16 ah_macRev;
+ u16 ah_phyRev;
+ u16 ah_analog5GhzRev;
+ u16 ah_analog2GhzRev;
+ u8 ah_decompMask[ATH9K_DECOMP_MASK_SIZE];
+ u32 ah_flags;
+ enum ath9k_opmode ah_opmode;
+ struct ath9k_ops_config ah_config;
+ struct ath9k_hw_capabilities ah_caps;
+ int16_t ah_powerLimit;
+ u16 ah_maxPowerLevel;
+ u32 ah_tpScale;
+ u16 ah_currentRD;
+ u16 ah_currentRDExt;
+ u16 ah_currentRDInUse;
+ u16 ah_currentRD5G;
+ u16 ah_currentRD2G;
+ char ah_iso[4];
+ enum start_adhoc_option ah_adHocMode;
+ bool ah_commonMode;
+ struct ath9k_channel ah_channels[150];
+ u32 ah_nchan;
+ struct ath9k_channel *ah_curchan;
+ u16 ah_rfsilent;
+ bool ah_rfkillEnabled;
+ bool ah_isPciExpress;
+ u16 ah_txTrigLevel;
+#ifndef ATH_NF_PER_CHAN
+ struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+#endif
+};
+
+struct chan_centers {
+ u16 synth_center;
+ u16 ctl_center;
+ u16 ext_center;
+};
+
+int ath_hal_getcapability(struct ath_hal *ah,
+ enum ath9k_capability_type type,
+ u32 capability,
+ u32 *result);
+const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
+ u32 mode);
+void ath9k_hw_detach(struct ath_hal *ah);
+struct ath_hal *ath9k_hw_attach(u16 devid,
+ struct ath_softc *sc,
+ void __iomem *mem,
+ int *error);
+bool ath9k_regd_init_channels(struct ath_hal *ah,
+ u32 maxchans, u32 *nchans,
+ u8 *regclassids,
+ u32 maxregids, u32 *nregids,
+ u16 cc,
+ bool enableOutdoor,
+ bool enableExtendedChannels);
+u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
+enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah,
+ enum ath9k_int ints);
+bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode,
+ struct ath9k_channel *chan,
+ enum ath9k_ht_macmode macmode,
+ u8 txchainmask, u8 rxchainmask,
+ enum ath9k_ht_extprotspacing extprotspacing,
+ bool bChannelChange,
+ int *status);
+bool ath9k_hw_phy_disable(struct ath_hal *ah);
+void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
+ bool *isCalDone);
+void ath9k_hw_ani_monitor(struct ath_hal *ah,
+ const struct ath9k_node_stats *stats,
+ struct ath9k_channel *chan);
+bool ath9k_hw_calibrate(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ u8 rxchainmask,
+ bool longcal,
+ bool *isCalDone);
+int16_t ath9k_hw_getchan_noise(struct ath_hal *ah,
+ struct ath9k_channel *chan);
+void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
+ u16 assocId);
+void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits);
+void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
+ u16 assocId);
+bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q);
+void ath9k_hw_reset_tsf(struct ath_hal *ah);
+bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry);
+bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry,
+ const u8 *mac);
+bool ath9k_hw_set_keycache_entry(struct ath_hal *ah,
+ u16 entry,
+ const struct ath9k_keyval *k,
+ const u8 *mac,
+ int xorKey);
+bool ath9k_hw_set_tsfadjust(struct ath_hal *ah,
+ u32 setting);
+void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore);
+bool ath9k_hw_intrpend(struct ath_hal *ah);
+bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked);
+bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah,
+ bool bIncTrigLevel);
+void ath9k_hw_procmibevent(struct ath_hal *ah,
+ const struct ath9k_node_stats *stats);
+bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set);
+void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode);
+bool ath9k_hw_phycounters(struct ath_hal *ah);
+bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry);
+bool ath9k_hw_getcapability(struct ath_hal *ah,
+ enum ath9k_capability_type type,
+ u32 capability,
+ u32 *result);
+bool ath9k_hw_setcapability(struct ath_hal *ah,
+ enum ath9k_capability_type type,
+ u32 capability,
+ u32 setting,
+ int *status);
+u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
+void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac);
+void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask);
+bool ath9k_hw_setbssidmask(struct ath_hal *ah,
+ const u8 *mask);
+bool ath9k_hw_setpower(struct ath_hal *ah,
+ enum ath9k_power_mode mode);
+enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah);
+u64 ath9k_hw_gettsf64(struct ath_hal *ah);
+u32 ath9k_hw_getdefantenna(struct ath_hal *ah);
+bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us);
+bool ath9k_hw_setantennaswitch(struct ath_hal *ah,
+ enum ath9k_ant_setting settings,
+ struct ath9k_channel *chan,
+ u8 *tx_chainmask,
+ u8 *rx_chainmask,
+ u8 *antenna_cfgd);
+void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna);
+int ath9k_hw_select_antconfig(struct ath_hal *ah,
+ u32 cfg);
+bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q,
+ u32 txdp);
+bool ath9k_hw_txstart(struct ath_hal *ah, u32 q);
+u16 ath9k_hw_computetxtime(struct ath_hal *ah,
+ const struct ath9k_rate_table *rates,
+ u32 frameLen, u16 rateix,
+ bool shortPreamble);
+void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
+ struct ath_desc *lastds,
+ u32 durUpdateEn, u32 rtsctsRate,
+ u32 rtsctsDuration,
+ struct ath9k_11n_rate_series series[],
+ u32 nseries, u32 flags);
+void ath9k_hw_set11n_burstduration(struct ath_hal *ah,
+ struct ath_desc *ds,
+ u32 burstDuration);
+void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds);
+u32 ath9k_hw_reverse_bits(u32 val, u32 n);
+bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q);
+u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan);
+u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
+ struct ath9k_channel *chan);
+u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags);
+bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
+ struct ath9k_tx_queue_info *qinfo);
+bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
+ const struct ath9k_tx_queue_info *qinfo);
+struct ath9k_channel *ath9k_regd_check_channel(struct ath_hal *ah,
+ const struct ath9k_channel *c);
+void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 pktLen, enum ath9k_pkt_type type,
+ u32 txPower, u32 keyIx,
+ enum ath9k_key_type keyType, u32 flags);
+bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 segLen, bool firstSeg,
+ bool lastSeg,
+ const struct ath_desc *ds0);
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
+ u32 *rxc_pcnt,
+ u32 *rxf_pcnt,
+ u32 *txf_pcnt);
+void ath9k_hw_dmaRegDump(struct ath_hal *ah);
+void ath9k_hw_beaconinit(struct ath_hal *ah,
+ u32 next_beacon, u32 beacon_period);
+void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
+ const struct ath9k_beacon_state *bs);
+bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 size, u32 flags);
+void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp);
+void ath9k_hw_rxena(struct ath_hal *ah);
+void ath9k_hw_setopmode(struct ath_hal *ah);
+bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac);
+void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0,
+ u32 filter1);
+u32 ath9k_hw_getrxfilter(struct ath_hal *ah);
+void ath9k_hw_startpcureceive(struct ath_hal *ah);
+void ath9k_hw_stoppcurecv(struct ath_hal *ah);
+bool ath9k_hw_stopdmarecv(struct ath_hal *ah);
+int ath9k_hw_rxprocdesc(struct ath_hal *ah,
+ struct ath_desc *ds, u32 pa,
+ struct ath_desc *nds, u64 tsf);
+u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q);
+int ath9k_hw_txprocdesc(struct ath_hal *ah,
+ struct ath_desc *ds);
+void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
+ u32 numDelims);
+void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
+ u32 aggrLen);
+void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds);
+bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q);
+void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs);
+void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds);
+void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah,
+ struct ath_desc *ds, u32 vmf);
+bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit);
+bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah);
+int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
+ const struct ath9k_tx_queue_info *qinfo);
+u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q);
+const char *ath9k_hw_probe(u16 vendorid, u16 devid);
+bool ath9k_hw_disable(struct ath_hal *ah);
+void ath9k_hw_rfdetach(struct ath_hal *ah);
+void ath9k_hw_get_channel_centers(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ struct chan_centers *centers);
+bool ath9k_get_channel_edges(struct ath_hal *ah,
+ u16 flags, u16 *low,
+ u16 *high);
+#endif
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c
new file mode 100644
index 00000000000..00a0eaa0886
--- /dev/null
+++ b/drivers/net/wireless/ath9k/beacon.c
@@ -0,0 +1,992 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+ /* Implementation of beacon processing. */
+
+#include <asm/unaligned.h>
+#include "core.h"
+
+/*
+ * Configure parameters for the beacon queue
+ *
+ * This function will modify certain transmit queue properties depending on
+ * the operating mode of the station (AP or AdHoc). Parameters are AIFS
+ * settings and channel width min/max
+*/
+
+static int ath_beaconq_config(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath9k_tx_queue_info qi;
+
+ ath9k_hw_get_txq_props(ah, sc->sc_bhalq, &qi);
+ if (sc->sc_opmode == ATH9K_M_HOSTAP) {
+ /* Always burst out beacon and CAB traffic. */
+ qi.tqi_aifs = 1;
+ qi.tqi_cwmin = 0;
+ qi.tqi_cwmax = 0;
+ } else {
+ /* Adhoc mode; important thing is to use 2x cwmin. */
+ qi.tqi_aifs = sc->sc_beacon_qi.tqi_aifs;
+ qi.tqi_cwmin = 2*sc->sc_beacon_qi.tqi_cwmin;
+ qi.tqi_cwmax = sc->sc_beacon_qi.tqi_cwmax;
+ }
+
+ if (!ath9k_hw_set_txq_props(ah, sc->sc_bhalq, &qi)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to update h/w beacon queue parameters\n",
+ __func__);
+ return 0;
+ } else {
+ ath9k_hw_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */
+ return 1;
+ }
+}
+
+/*
+ * Setup the beacon frame for transmit.
+ *
+ * Associates the beacon frame buffer with a transmit descriptor. Will set
+ * up all required antenna switch parameters, rate codes, and channel flags.
+ * Beacons are always sent out at the lowest rate, and are not retried.
+*/
+
+static void ath_beacon_setup(struct ath_softc *sc,
+ struct ath_vap *avp, struct ath_buf *bf)
+{
+ struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_desc *ds;
+ int flags, antenna;
+ const struct ath9k_rate_table *rt;
+ u8 rix, rate;
+ int ctsrate = 0;
+ int ctsduration = 0;
+ struct ath9k_11n_rate_series series[4];
+
+ DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n",
+ __func__, skb, skb->len);
+
+ /* setup descriptors */
+ ds = bf->bf_desc;
+
+ flags = ATH9K_TXDESC_NOACK;
+
+ if (sc->sc_opmode == ATH9K_M_IBSS &&
+ (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
+ ds->ds_link = bf->bf_daddr; /* self-linked */
+ flags |= ATH9K_TXDESC_VEOL;
+ /* Let hardware handle antenna switching. */
+ antenna = 0;
+ } else {
+ ds->ds_link = 0;
+ /*
+ * Switch antenna every beacon.
+ * Should only switch every beacon period, not for every
+ * SWBA's
+ * XXX assumes two antenna
+ */
+ antenna = ((sc->ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1);
+ }
+
+ ds->ds_data = bf->bf_buf_addr;
+
+ /*
+ * Calculate rate code.
+ * XXX everything at min xmit rate
+ */
+ rix = 0;
+ rt = sc->sc_currates;
+ rate = rt->info[rix].rateCode;
+ if (sc->sc_flags & ATH_PREAMBLE_SHORT)
+ rate |= rt->info[rix].shortPreamble;
+
+ ath9k_hw_set11n_txdesc(ah, ds
+ , skb->len + FCS_LEN /* frame length */
+ , ATH9K_PKT_TYPE_BEACON /* Atheros packet type */
+ , avp->av_btxctl.txpower /* txpower XXX */
+ , ATH9K_TXKEYIX_INVALID /* no encryption */
+ , ATH9K_KEY_TYPE_CLEAR /* no encryption */
+ , flags /* no ack, veol for beacons */
+ );
+
+ /* NB: beacon's BufLen must be a multiple of 4 bytes */
+ ath9k_hw_filltxdesc(ah, ds
+ , roundup(skb->len, 4) /* buffer length */
+ , true /* first segment */
+ , true /* last segment */
+ , ds /* first descriptor */
+ );
+
+ memzero(series, sizeof(struct ath9k_11n_rate_series) * 4);
+ series[0].Tries = 1;
+ series[0].Rate = rate;
+ series[0].ChSel = sc->sc_tx_chainmask;
+ series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
+ ath9k_hw_set11n_ratescenario(ah, ds, ds, 0,
+ ctsrate, ctsduration, series, 4, 0);
+}
+
+/* Move everything from the vap's mcast queue to the hardware cab queue.
+ * Caller must hold mcasq lock and cabq lock
+ * XXX MORE_DATA bit?
+ */
+static void empty_mcastq_into_cabq(struct ath_hal *ah,
+ struct ath_txq *mcastq, struct ath_txq *cabq)
+{
+ struct ath_buf *bfmcast;
+
+ BUG_ON(list_empty(&mcastq->axq_q));
+
+ bfmcast = list_first_entry(&mcastq->axq_q, struct ath_buf, list);
+
+ /* link the descriptors */
+ if (!cabq->axq_link)
+ ath9k_hw_puttxbuf(ah, cabq->axq_qnum, bfmcast->bf_daddr);
+ else
+ *cabq->axq_link = bfmcast->bf_daddr;
+
+ /* append the private vap mcast list to the cabq */
+
+ cabq->axq_depth += mcastq->axq_depth;
+ cabq->axq_totalqueued += mcastq->axq_totalqueued;
+ cabq->axq_linkbuf = mcastq->axq_linkbuf;
+ cabq->axq_link = mcastq->axq_link;
+ list_splice_tail_init(&mcastq->axq_q, &cabq->axq_q);
+ mcastq->axq_depth = 0;
+ mcastq->axq_totalqueued = 0;
+ mcastq->axq_linkbuf = NULL;
+ mcastq->axq_link = NULL;
+}
+
+/* This is only run at DTIM. We move everything from the vap's mcast queue
+ * to the hardware cab queue. Caller must hold the mcastq lock. */
+static void trigger_mcastq(struct ath_hal *ah,
+ struct ath_txq *mcastq, struct ath_txq *cabq)
+{
+ spin_lock_bh(&cabq->axq_lock);
+
+ if (!list_empty(&mcastq->axq_q))
+ empty_mcastq_into_cabq(ah, mcastq, cabq);
+
+ /* cabq is gated by beacon so it is safe to start here */
+ if (!list_empty(&cabq->axq_q))
+ ath9k_hw_txstart(ah, cabq->axq_qnum);
+
+ spin_unlock_bh(&cabq->axq_lock);
+}
+
+/*
+ * Generate beacon frame and queue cab data for a vap.
+ *
+ * Updates the contents of the beacon frame. It is assumed that the buffer for
+ * the beacon frame has been allocated in the ATH object, and simply needs to
+ * be filled for this cycle. Also, any CAB (crap after beacon?) traffic will
+ * be added to the beacon frame at this point.
+*/
+static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf;
+ struct ath_vap *avp;
+ struct sk_buff *skb;
+ int cabq_depth;
+ int mcastq_depth;
+ int is_beacon_dtim = 0;
+ unsigned int curlen;
+ struct ath_txq *cabq;
+ struct ath_txq *mcastq;
+ struct ieee80211_tx_info *info;
+ avp = sc->sc_vaps[if_id];
+
+ mcastq = &avp->av_mcastq;
+ cabq = sc->sc_cabq;
+
+ ASSERT(avp);
+
+ if (avp->av_bcbuf == NULL) {
+ DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n",
+ __func__, avp, avp->av_bcbuf);
+ return NULL;
+ }
+ bf = avp->av_bcbuf;
+ skb = (struct sk_buff *) bf->bf_mpdu;
+
+ /*
+ * Update dynamic beacon contents. If this returns
+ * non-zero then we need to remap the memory because
+ * the beacon frame changed size (probably because
+ * of the TIM bitmap).
+ */
+ curlen = skb->len;
+
+ info = IEEE80211_SKB_CB(skb);
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ /*
+ * TODO: make sure the seq# gets assigned properly (vs. other
+ * TX frames)
+ */
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ sc->seq_no += 0x10;
+ hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+ }
+
+ /* XXX: spin_lock_bh should not be used here, but sparse bitches
+ * otherwise. We should fix sparse :) */
+ spin_lock_bh(&mcastq->axq_lock);
+ mcastq_depth = avp->av_mcastq.axq_depth;
+
+ if (ath_update_beacon(sc, if_id, &avp->av_boff, skb, mcastq_depth) ==
+ 1) {
+ ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
+ get_dma_mem_context(bf, bf_dmacontext));
+ bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE,
+ get_dma_mem_context(bf, bf_dmacontext));
+ } else {
+ pci_dma_sync_single_for_cpu(sc->pdev,
+ bf->bf_buf_addr,
+ skb_tailroom(skb),
+ PCI_DMA_TODEVICE);
+ }
+
+ /*
+ * if the CABQ traffic from previous DTIM is pending and the current
+ * beacon is also a DTIM.
+ * 1) if there is only one vap let the cab traffic continue.
+ * 2) if there are more than one vap and we are using staggered
+ * beacons, then drain the cabq by dropping all the frames in
+ * the cabq so that the current vaps cab traffic can be scheduled.
+ */
+ spin_lock_bh(&cabq->axq_lock);
+ cabq_depth = cabq->axq_depth;
+ spin_unlock_bh(&cabq->axq_lock);
+
+ is_beacon_dtim = avp->av_boff.bo_tim[4] & 1;
+
+ if (mcastq_depth && is_beacon_dtim && cabq_depth) {
+ /*
+ * Unlock the cabq lock as ath_tx_draintxq acquires
+ * the lock again which is a common function and that
+ * acquires txq lock inside.
+ */
+ if (sc->sc_nvaps > 1) {
+ ath_tx_draintxq(sc, cabq, false);
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "%s: flush previous cabq traffic\n", __func__);
+ }
+ }
+
+ /* Construct tx descriptor. */
+ ath_beacon_setup(sc, avp, bf);
+
+ /*
+ * Enable the CAB queue before the beacon queue to
+ * insure cab frames are triggered by this beacon.
+ */
+ if (is_beacon_dtim)
+ trigger_mcastq(ah, mcastq, cabq);
+
+ spin_unlock_bh(&mcastq->axq_lock);
+ return bf;
+}
+
+/*
+ * Startup beacon transmission for adhoc mode when they are sent entirely
+ * by the hardware using the self-linked descriptor + veol trick.
+*/
+
+static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf;
+ struct ath_vap *avp;
+ struct sk_buff *skb;
+
+ avp = sc->sc_vaps[if_id];
+ ASSERT(avp);
+
+ if (avp->av_bcbuf == NULL) {
+ DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n",
+ __func__, avp, avp != NULL ? avp->av_bcbuf : NULL);
+ return;
+ }
+ bf = avp->av_bcbuf;
+ skb = (struct sk_buff *) bf->bf_mpdu;
+
+ /* Construct tx descriptor. */
+ ath_beacon_setup(sc, avp, bf);
+
+ /* NB: caller is known to have already stopped tx dma */
+ ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr);
+ ath9k_hw_txstart(ah, sc->sc_bhalq);
+ DPRINTF(sc, ATH_DBG_BEACON, "%s: TXDP%u = %llx (%p)\n", __func__,
+ sc->sc_bhalq, ito64(bf->bf_daddr), bf->bf_desc);
+}
+
+/*
+ * Setup a h/w transmit queue for beacons.
+ *
+ * This function allocates an information structure (struct ath9k_txq_info)
+ * on the stack, sets some specific parameters (zero out channel width
+ * min/max, and enable aifs). The info structure does not need to be
+ * persistant.
+*/
+
+int ath_beaconq_setup(struct ath_hal *ah)
+{
+ struct ath9k_tx_queue_info qi;
+
+ memzero(&qi, sizeof(qi));
+ qi.tqi_aifs = 1;
+ qi.tqi_cwmin = 0;
+ qi.tqi_cwmax = 0;
+ /* NB: don't enable any interrupts */
+ return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
+}
+
+
+/*
+ * Allocate and setup an initial beacon frame.
+ *
+ * Allocate a beacon state variable for a specific VAP instance created on
+ * the ATH interface. This routine also calculates the beacon "slot" for
+ * staggared beacons in the mBSSID case.
+*/
+
+int ath_beacon_alloc(struct ath_softc *sc, int if_id)
+{
+ struct ath_vap *avp;
+ struct ieee80211_hdr *wh;
+ struct ath_buf *bf;
+ struct sk_buff *skb;
+
+ avp = sc->sc_vaps[if_id];
+ ASSERT(avp);
+
+ /* Allocate a beacon descriptor if we haven't done so. */
+ if (!avp->av_bcbuf) {
+ /*
+ * Allocate beacon state for hostap/ibss. We know
+ * a buffer is available.
+ */
+
+ avp->av_bcbuf = list_first_entry(&sc->sc_bbuf,
+ struct ath_buf, list);
+ list_del(&avp->av_bcbuf->list);
+
+ if (sc->sc_opmode == ATH9K_M_HOSTAP ||
+ !(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
+ int slot;
+ /*
+ * Assign the vap to a beacon xmit slot. As
+ * above, this cannot fail to find one.
+ */
+ avp->av_bslot = 0;
+ for (slot = 0; slot < ATH_BCBUF; slot++)
+ if (sc->sc_bslot[slot] == ATH_IF_ID_ANY) {
+ /*
+ * XXX hack, space out slots to better
+ * deal with misses
+ */
+ if (slot+1 < ATH_BCBUF &&
+ sc->sc_bslot[slot+1] ==
+ ATH_IF_ID_ANY) {
+ avp->av_bslot = slot+1;
+ break;
+ }
+ avp->av_bslot = slot;
+ /* NB: keep looking for a double slot */
+ }
+ BUG_ON(sc->sc_bslot[avp->av_bslot] != ATH_IF_ID_ANY);
+ sc->sc_bslot[avp->av_bslot] = if_id;
+ sc->sc_nbcnvaps++;
+ }
+ }
+
+ /* release the previous beacon frame , if it already exists. */
+ bf = avp->av_bcbuf;
+ if (bf->bf_mpdu != NULL) {
+ skb = (struct sk_buff *)bf->bf_mpdu;
+ ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
+ get_dma_mem_context(bf, bf_dmacontext));
+ dev_kfree_skb_any(skb);
+ bf->bf_mpdu = NULL;
+ }
+
+ /*
+ * NB: the beacon data buffer must be 32-bit aligned;
+ * we assume the wbuf routines will return us something
+ * with this alignment (perhaps should assert).
+ * FIXME: Fill avp->av_boff.bo_tim,avp->av_btxctl.txpower and
+ * avp->av_btxctl.shortPreamble
+ */
+ skb = ieee80211_beacon_get(sc->hw, avp->av_if_data);
+ if (skb == NULL) {
+ DPRINTF(sc, ATH_DBG_BEACON, "%s: cannot get skb\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ /*
+ * Calculate a TSF adjustment factor required for
+ * staggered beacons. Note that we assume the format
+ * of the beacon frame leaves the tstamp field immediately
+ * following the header.
+ */
+ if (avp->av_bslot > 0) {
+ u64 tsfadjust;
+ __le64 val;
+ int intval;
+
+ /* FIXME: Use default value for now: Sujith */
+
+ intval = ATH_DEFAULT_BINTVAL;
+
+ /*
+ * The beacon interval is in TU's; the TSF in usecs.
+ * We figure out how many TU's to add to align the
+ * timestamp then convert to TSF units and handle
+ * byte swapping before writing it in the frame.
+ * The hardware will then add this each time a beacon
+ * frame is sent. Note that we align vap's 1..N
+ * and leave vap 0 untouched. This means vap 0
+ * has a timestamp in one beacon interval while the
+ * others get a timestamp aligned to the next interval.
+ */
+ tsfadjust = (intval * (ATH_BCBUF - avp->av_bslot)) / ATH_BCBUF;
+ val = cpu_to_le64(tsfadjust << 10); /* TU->TSF */
+
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "%s: %s beacons, bslot %d intval %u tsfadjust %llu\n",
+ __func__, "stagger",
+ avp->av_bslot, intval, (unsigned long long)tsfadjust);
+
+ wh = (struct ieee80211_hdr *)skb->data;
+ memcpy(&wh[1], &val, sizeof(val));
+ }
+
+ bf->bf_buf_addr = ath_skb_map_single(sc, skb, PCI_DMA_TODEVICE,
+ get_dma_mem_context(bf, bf_dmacontext));
+ bf->bf_mpdu = skb;
+
+ return 0;
+}
+
+/*
+ * Reclaim beacon resources and return buffer to the pool.
+ *
+ * Checks the VAP to put the beacon frame buffer back to the ATH object
+ * queue, and de-allocates any wbuf frames that were sent as CAB traffic.
+*/
+
+void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
+{
+ if (avp->av_bcbuf != NULL) {
+ struct ath_buf *bf;
+
+ if (avp->av_bslot != -1) {
+ sc->sc_bslot[avp->av_bslot] = ATH_IF_ID_ANY;
+ sc->sc_nbcnvaps--;
+ }
+
+ bf = avp->av_bcbuf;
+ if (bf->bf_mpdu != NULL) {
+ struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
+ ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
+ get_dma_mem_context(bf, bf_dmacontext));
+ dev_kfree_skb_any(skb);
+ bf->bf_mpdu = NULL;
+ }
+ list_add_tail(&bf->list, &sc->sc_bbuf);
+
+ avp->av_bcbuf = NULL;
+ }
+}
+
+/*
+ * Reclaim beacon resources and return buffer to the pool.
+ *
+ * This function will free any wbuf frames that are still attached to the
+ * beacon buffers in the ATH object. Note that this does not de-allocate
+ * any wbuf objects that are in the transmit queue and have not yet returned
+ * to the ATH object.
+*/
+
+void ath_beacon_free(struct ath_softc *sc)
+{
+ struct ath_buf *bf;
+
+ list_for_each_entry(bf, &sc->sc_bbuf, list) {
+ if (bf->bf_mpdu != NULL) {
+ struct sk_buff *skb = (struct sk_buff *) bf->bf_mpdu;
+ ath_skb_unmap_single(sc, skb, PCI_DMA_TODEVICE,
+ get_dma_mem_context(bf, bf_dmacontext));
+ dev_kfree_skb_any(skb);
+ bf->bf_mpdu = NULL;
+ }
+ }
+}
+
+/*
+ * Tasklet for Sending Beacons
+ *
+ * Transmit one or more beacon frames at SWBA. Dynamic updates to the frame
+ * contents are done as needed and the slot time is also adjusted based on
+ * current state.
+ *
+ * This tasklet is not scheduled, it's called in ISR context.
+*/
+
+void ath9k_beacon_tasklet(unsigned long data)
+{
+#define TSF_TO_TU(_h,_l) \
+ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
+
+ struct ath_softc *sc = (struct ath_softc *)data;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf = NULL;
+ int slot, if_id;
+ u32 bfaddr;
+ u32 rx_clear = 0, rx_frame = 0, tx_frame = 0;
+ u32 show_cycles = 0;
+ u32 bc = 0; /* beacon count */
+ u64 tsf;
+ u32 tsftu;
+ u16 intval;
+
+ if (sc->sc_noreset) {
+ show_cycles = ath9k_hw_GetMibCycleCountsPct(ah,
+ &rx_clear,
+ &rx_frame,
+ &tx_frame);
+ }
+
+ /*
+ * Check if the previous beacon has gone out. If
+ * not don't try to post another, skip this period
+ * and wait for the next. Missed beacons indicate
+ * a problem and should not occur. If we miss too
+ * many consecutive beacons reset the device.
+ */
+ if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) {
+ sc->sc_bmisscount++;
+ /* XXX: doth needs the chanchange IE countdown decremented.
+ * We should consider adding a mac80211 call to indicate
+ * a beacon miss so appropriate action could be taken
+ * (in that layer).
+ */
+ if (sc->sc_bmisscount < BSTUCK_THRESH) {
+ if (sc->sc_noreset) {
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "%s: missed %u consecutive beacons\n",
+ __func__, sc->sc_bmisscount);
+ if (show_cycles) {
+ /*
+ * Display cycle counter stats
+ * from HW to aide in debug of
+ * stickiness.
+ */
+ DPRINTF(sc,
+ ATH_DBG_BEACON,
+ "%s: busy times: rx_clear=%d, "
+ "rx_frame=%d, tx_frame=%d\n",
+ __func__, rx_clear, rx_frame,
+ tx_frame);
+ } else {
+ DPRINTF(sc,
+ ATH_DBG_BEACON,
+ "%s: unable to obtain "
+ "busy times\n", __func__);
+ }
+ } else {
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "%s: missed %u consecutive beacons\n",
+ __func__, sc->sc_bmisscount);
+ }
+ } else if (sc->sc_bmisscount >= BSTUCK_THRESH) {
+ if (sc->sc_noreset) {
+ if (sc->sc_bmisscount == BSTUCK_THRESH) {
+ DPRINTF(sc,
+ ATH_DBG_BEACON,
+ "%s: beacon is officially "
+ "stuck\n", __func__);
+ ath9k_hw_dmaRegDump(ah);
+ }
+ } else {
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "%s: beacon is officially stuck\n",
+ __func__);
+ ath_bstuck_process(sc);
+ }
+ }
+
+ return;
+ }
+ if (sc->sc_bmisscount != 0) {
+ if (sc->sc_noreset) {
+ DPRINTF(sc,
+ ATH_DBG_BEACON,
+ "%s: resume beacon xmit after %u misses\n",
+ __func__, sc->sc_bmisscount);
+ } else {
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "%s: resume beacon xmit after %u misses\n",
+ __func__, sc->sc_bmisscount);
+ }
+ sc->sc_bmisscount = 0;
+ }
+
+ /*
+ * Generate beacon frames. we are sending frames
+ * staggered so calculate the slot for this frame based
+ * on the tsf to safeguard against missing an swba.
+ */
+
+ /* FIXME: Use default value for now - Sujith */
+ intval = ATH_DEFAULT_BINTVAL;
+
+ tsf = ath9k_hw_gettsf64(ah);
+ tsftu = TSF_TO_TU(tsf>>32, tsf);
+ slot = ((tsftu % intval) * ATH_BCBUF) / intval;
+ if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF];
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
+ __func__, slot, (unsigned long long) tsf, tsftu,
+ intval, if_id);
+ bfaddr = 0;
+ if (if_id != ATH_IF_ID_ANY) {
+ bf = ath_beacon_generate(sc, if_id);
+ if (bf != NULL) {
+ bfaddr = bf->bf_daddr;
+ bc = 1;
+ }
+ }
+ /*
+ * Handle slot time change when a non-ERP station joins/leaves
+ * an 11g network. The 802.11 layer notifies us via callback,
+ * we mark updateslot, then wait one beacon before effecting
+ * the change. This gives associated stations at least one
+ * beacon interval to note the state change.
+ *
+ * NB: The slot time change state machine is clocked according
+ * to whether we are bursting or staggering beacons. We
+ * recognize the request to update and record the current
+ * slot then don't transition until that slot is reached
+ * again. If we miss a beacon for that slot then we'll be
+ * slow to transition but we'll be sure at least one beacon
+ * interval has passed. When bursting slot is always left
+ * set to ATH_BCBUF so this check is a noop.
+ */
+ /* XXX locking */
+ if (sc->sc_updateslot == UPDATE) {
+ sc->sc_updateslot = COMMIT; /* commit next beacon */
+ sc->sc_slotupdate = slot;
+ } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot)
+ ath_setslottime(sc); /* commit change to hardware */
+
+ if (bfaddr != 0) {
+ /*
+ * Stop any current dma and put the new frame(s) on the queue.
+ * This should never fail since we check above that no frames
+ * are still pending on the queue.
+ */
+ if (!ath9k_hw_stoptxdma(ah, sc->sc_bhalq)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: beacon queue %u did not stop?\n",
+ __func__, sc->sc_bhalq);
+ /* NB: the HAL still stops DMA, so proceed */
+ }
+
+ /* NB: cabq traffic should already be queued and primed */
+ ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bfaddr);
+ ath9k_hw_txstart(ah, sc->sc_bhalq);
+
+ sc->ast_be_xmit += bc; /* XXX per-vap? */
+ }
+#undef TSF_TO_TU
+}
+
+/*
+ * Tasklet for Beacon Stuck processing
+ *
+ * Processing for Beacon Stuck.
+ * Basically calls the ath_internal_reset function to reset the chip.
+*/
+
+void ath_bstuck_process(struct ath_softc *sc)
+{
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "%s: stuck beacon; resetting (bmiss count %u)\n",
+ __func__, sc->sc_bmisscount);
+ ath_internal_reset(sc);
+}
+
+/*
+ * Configure the beacon and sleep timers.
+ *
+ * When operating as an AP this resets the TSF and sets
+ * up the hardware to notify us when we need to issue beacons.
+ *
+ * When operating in station mode this sets up the beacon
+ * timers according to the timestamp of the last received
+ * beacon and the current TSF, configures PCF and DTIM
+ * handling, programs the sleep registers so the hardware
+ * will wakeup in time to receive beacons, and configures
+ * the beacon miss handling so we'll receive a BMISS
+ * interrupt when we stop seeing beacons from the AP
+ * we've associated with.
+ */
+
+void ath_beacon_config(struct ath_softc *sc, int if_id)
+{
+#define TSF_TO_TU(_h,_l) \
+ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
+ struct ath_hal *ah = sc->sc_ah;
+ u32 nexttbtt, intval;
+ struct ath_beacon_config conf;
+ enum ath9k_opmode av_opmode;
+
+ if (if_id != ATH_IF_ID_ANY)
+ av_opmode = sc->sc_vaps[if_id]->av_opmode;
+ else
+ av_opmode = sc->sc_opmode;
+
+ memzero(&conf, sizeof(struct ath_beacon_config));
+
+ /* FIXME: Use default values for now - Sujith */
+ /* Query beacon configuration first */
+ /*
+ * Protocol stack doesn't support dynamic beacon configuration,
+ * use default configurations.
+ */
+ conf.beacon_interval = ATH_DEFAULT_BINTVAL;
+ conf.listen_interval = 1;
+ conf.dtim_period = conf.beacon_interval;
+ conf.dtim_count = 1;
+ conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
+
+ /* extract tstamp from last beacon and convert to TU */
+ nexttbtt = TSF_TO_TU(get_unaligned_le32(conf.u.last_tstamp + 4),
+ get_unaligned_le32(conf.u.last_tstamp));
+ /* XXX conditionalize multi-bss support? */
+ if (sc->sc_opmode == ATH9K_M_HOSTAP) {
+ /*
+ * For multi-bss ap support beacons are either staggered
+ * evenly over N slots or burst together. For the former
+ * arrange for the SWBA to be delivered for each slot.
+ * Slots that are not occupied will generate nothing.
+ */
+ /* NB: the beacon interval is kept internally in TU's */
+ intval = conf.beacon_interval & ATH9K_BEACON_PERIOD;
+ intval /= ATH_BCBUF; /* for staggered beacons */
+ } else {
+ intval = conf.beacon_interval & ATH9K_BEACON_PERIOD;
+ }
+
+ if (nexttbtt == 0) /* e.g. for ap mode */
+ nexttbtt = intval;
+ else if (intval) /* NB: can be 0 for monitor mode */
+ nexttbtt = roundup(nexttbtt, intval);
+ DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
+ __func__, nexttbtt, intval, conf.beacon_interval);
+ /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */
+ if (sc->sc_opmode == ATH9K_M_STA) {
+ struct ath9k_beacon_state bs;
+ u64 tsf;
+ u32 tsftu;
+ int dtimperiod, dtimcount, sleepduration;
+ int cfpperiod, cfpcount;
+
+ /*
+ * Setup dtim and cfp parameters according to
+ * last beacon we received (which may be none).
+ */
+ dtimperiod = conf.dtim_period;
+ if (dtimperiod <= 0) /* NB: 0 if not known */
+ dtimperiod = 1;
+ dtimcount = conf.dtim_count;
+ if (dtimcount >= dtimperiod) /* NB: sanity check */
+ dtimcount = 0; /* XXX? */
+ cfpperiod = 1; /* NB: no PCF support yet */
+ cfpcount = 0;
+
+ sleepduration = conf.listen_interval * intval;
+ if (sleepduration <= 0)
+ sleepduration = intval;
+
+#define FUDGE 2
+ /*
+ * Pull nexttbtt forward to reflect the current
+ * TSF and calculate dtim+cfp state for the result.
+ */
+ tsf = ath9k_hw_gettsf64(ah);
+ tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
+ do {
+ nexttbtt += intval;
+ if (--dtimcount < 0) {
+ dtimcount = dtimperiod - 1;
+ if (--cfpcount < 0)
+ cfpcount = cfpperiod - 1;
+ }
+ } while (nexttbtt < tsftu);
+#undef FUDGE
+ memzero(&bs, sizeof(bs));
+ bs.bs_intval = intval;
+ bs.bs_nexttbtt = nexttbtt;
+ bs.bs_dtimperiod = dtimperiod*intval;
+ bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
+ bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
+ bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
+ bs.bs_cfpmaxduration = 0;
+ /*
+ * Calculate the number of consecutive beacons to miss
+ * before taking a BMISS interrupt. The configuration
+ * is specified in TU so we only need calculate based
+ * on the beacon interval. Note that we clamp the
+ * result to at most 15 beacons.
+ */
+ if (sleepduration > intval) {
+ bs.bs_bmissthreshold =
+ conf.listen_interval *
+ ATH_DEFAULT_BMISS_LIMIT / 2;
+ } else {
+ bs.bs_bmissthreshold =
+ DIV_ROUND_UP(conf.bmiss_timeout, intval);
+ if (bs.bs_bmissthreshold > 15)
+ bs.bs_bmissthreshold = 15;
+ else if (bs.bs_bmissthreshold <= 0)
+ bs.bs_bmissthreshold = 1;
+ }
+
+ /*
+ * Calculate sleep duration. The configuration is
+ * given in ms. We insure a multiple of the beacon
+ * period is used. Also, if the sleep duration is
+ * greater than the DTIM period then it makes senses
+ * to make it a multiple of that.
+ *
+ * XXX fixed at 100ms
+ */
+
+ bs.bs_sleepduration =
+ roundup(IEEE80211_MS_TO_TU(100), sleepduration);
+ if (bs.bs_sleepduration > bs.bs_dtimperiod)
+ bs.bs_sleepduration = bs.bs_dtimperiod;
+
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "%s: tsf %llu "
+ "tsf:tu %u "
+ "intval %u "
+ "nexttbtt %u "
+ "dtim %u "
+ "nextdtim %u "
+ "bmiss %u "
+ "sleep %u "
+ "cfp:period %u "
+ "maxdur %u "
+ "next %u "
+ "timoffset %u\n"
+ , __func__
+ , (unsigned long long)tsf, tsftu
+ , bs.bs_intval
+ , bs.bs_nexttbtt
+ , bs.bs_dtimperiod
+ , bs.bs_nextdtim
+ , bs.bs_bmissthreshold
+ , bs.bs_sleepduration
+ , bs.bs_cfpperiod
+ , bs.bs_cfpmaxduration
+ , bs.bs_cfpnext
+ , bs.bs_timoffset
+ );
+
+ ath9k_hw_set_interrupts(ah, 0);
+ ath9k_hw_set_sta_beacon_timers(ah, &bs);
+ sc->sc_imask |= ATH9K_INT_BMISS;
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+ } else {
+ u64 tsf;
+ u32 tsftu;
+ ath9k_hw_set_interrupts(ah, 0);
+ if (nexttbtt == intval)
+ intval |= ATH9K_BEACON_RESET_TSF;
+ if (sc->sc_opmode == ATH9K_M_IBSS) {
+ /*
+ * Pull nexttbtt forward to reflect the current
+ * TSF .
+ */
+#define FUDGE 2
+ if (!(intval & ATH9K_BEACON_RESET_TSF)) {
+ tsf = ath9k_hw_gettsf64(ah);
+ tsftu = TSF_TO_TU((u32)(tsf>>32),
+ (u32)tsf) + FUDGE;
+ do {
+ nexttbtt += intval;
+ } while (nexttbtt < tsftu);
+ }
+#undef FUDGE
+ DPRINTF(sc, ATH_DBG_BEACON,
+ "%s: IBSS nexttbtt %u intval %u (%u)\n",
+ __func__, nexttbtt,
+ intval & ~ATH9K_BEACON_RESET_TSF,
+ conf.beacon_interval);
+
+ /*
+ * In IBSS mode enable the beacon timers but only
+ * enable SWBA interrupts if we need to manually
+ * prepare beacon frames. Otherwise we use a
+ * self-linked tx descriptor and let the hardware
+ * deal with things.
+ */
+ intval |= ATH9K_BEACON_ENA;
+ if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
+ sc->sc_imask |= ATH9K_INT_SWBA;
+ ath_beaconq_config(sc);
+ } else if (sc->sc_opmode == ATH9K_M_HOSTAP) {
+ /*
+ * In AP mode we enable the beacon timers and
+ * SWBA interrupts to prepare beacon frames.
+ */
+ intval |= ATH9K_BEACON_ENA;
+ sc->sc_imask |= ATH9K_INT_SWBA; /* beacon prepare */
+ ath_beaconq_config(sc);
+ }
+ ath9k_hw_beaconinit(ah, nexttbtt, intval);
+ sc->sc_bmisscount = 0;
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+ /*
+ * When using a self-linked beacon descriptor in
+ * ibss mode load it once here.
+ */
+ if (sc->sc_opmode == ATH9K_M_IBSS &&
+ (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL))
+ ath_beacon_start_adhoc(sc, 0);
+ }
+#undef TSF_TO_TU
+}
+
+/* Function to collect beacon rssi data and resync beacon if necessary */
+
+void ath_beacon_sync(struct ath_softc *sc, int if_id)
+{
+ /*
+ * Resync beacon timers using the tsf of the
+ * beacon frame we just received.
+ */
+ ath_beacon_config(sc, if_id);
+ sc->sc_beacons = 1;
+}
diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c
new file mode 100644
index 00000000000..f6c45288d0e
--- /dev/null
+++ b/drivers/net/wireless/ath9k/core.c
@@ -0,0 +1,1923 @@
+/*
+ * Copyright (c) 2008, Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+ /* Implementation of the main "ATH" layer. */
+
+#include "core.h"
+#include "regd.h"
+
+static int ath_outdoor; /* enable outdoor use */
+
+static const u8 ath_bcast_mac[ETH_ALEN] =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+static u32 ath_chainmask_sel_up_rssi_thres =
+ ATH_CHAINMASK_SEL_UP_RSSI_THRES;
+static u32 ath_chainmask_sel_down_rssi_thres =
+ ATH_CHAINMASK_SEL_DOWN_RSSI_THRES;
+static u32 ath_chainmask_sel_period =
+ ATH_CHAINMASK_SEL_TIMEOUT;
+
+/* return bus cachesize in 4B word units */
+
+static void bus_read_cachesize(struct ath_softc *sc, int *csz)
+{
+ u8 u8tmp;
+
+ pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp);
+ *csz = (int)u8tmp;
+
+ /*
+ * This check was put in to avoid "unplesant" consequences if
+ * the bootrom has not fully initialized all PCI devices.
+ * Sometimes the cache line size register is not set
+ */
+
+ if (*csz == 0)
+ *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */
+}
+
+/*
+ * Set current operating mode
+ *
+ * This function initializes and fills the rate table in the ATH object based
+ * on the operating mode. The blink rates are also set up here, although
+ * they have been superceeded by the ath_led module.
+*/
+
+static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
+{
+ const struct ath9k_rate_table *rt;
+ int i;
+
+ memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap));
+ rt = ath9k_hw_getratetable(sc->sc_ah, mode);
+ BUG_ON(!rt);
+
+ for (i = 0; i < rt->rateCount; i++)
+ sc->sc_rixmap[rt->info[i].rateCode] = (u8) i;
+
+ memzero(sc->sc_hwmap, sizeof(sc->sc_hwmap));
+ for (i = 0; i < 256; i++) {
+ u8 ix = rt->rateCodeToIndex[i];
+
+ if (ix == 0xff)
+ continue;
+
+ sc->sc_hwmap[i].ieeerate =
+ rt->info[ix].dot11Rate & IEEE80211_RATE_VAL;
+ sc->sc_hwmap[i].rateKbps = rt->info[ix].rateKbps;
+
+ if (rt->info[ix].shortPreamble ||
+ rt->info[ix].phy == PHY_OFDM) {
+ /* XXX: Handle this */
+ }
+
+ /* NB: this uses the last entry if the rate isn't found */
+ /* XXX beware of overlow */
+ }
+ sc->sc_currates = rt;
+ sc->sc_curmode = mode;
+ /*
+ * All protection frames are transmited at 2Mb/s for
+ * 11g, otherwise at 1Mb/s.
+ * XXX select protection rate index from rate table.
+ */
+ sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0);
+}
+
+/*
+ * Set up rate table (legacy rates)
+ */
+static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ const struct ath9k_rate_table *rt = NULL;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_rate *rate;
+ int i, maxrates;
+
+ switch (band) {
+ case IEEE80211_BAND_2GHZ:
+ rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11G);
+ break;
+ case IEEE80211_BAND_5GHZ:
+ rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11A);
+ break;
+ default:
+ break;
+ }
+
+ if (rt == NULL)
+ return;
+
+ sband = &sc->sbands[band];
+ rate = sc->rates[band];
+
+ if (rt->rateCount > ATH_RATE_MAX)
+ maxrates = ATH_RATE_MAX;
+ else
+ maxrates = rt->rateCount;
+
+ for (i = 0; i < maxrates; i++) {
+ rate[i].bitrate = rt->info[i].rateKbps / 100;
+ rate[i].hw_value = rt->info[i].rateCode;
+ sband->n_bitrates++;
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: Rate: %2dMbps, ratecode: %2d\n",
+ __func__,
+ rate[i].bitrate / 10,
+ rate[i].hw_value);
+ }
+}
+
+/*
+ * Set up channel list
+ */
+static int ath_setup_channels(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int nchan, i, a = 0, b = 0;
+ u8 regclassids[ATH_REGCLASSIDS_MAX];
+ u32 nregclass = 0;
+ struct ieee80211_supported_band *band_2ghz;
+ struct ieee80211_supported_band *band_5ghz;
+ struct ieee80211_channel *chan_2ghz;
+ struct ieee80211_channel *chan_5ghz;
+ struct ath9k_channel *c;
+
+ /* Fill in ah->ah_channels */
+ if (!ath9k_regd_init_channels(ah,
+ ATH_CHAN_MAX,
+ (u32 *)&nchan,
+ regclassids,
+ ATH_REGCLASSIDS_MAX,
+ &nregclass,
+ CTRY_DEFAULT,
+ false,
+ 1)) {
+ u32 rd = ah->ah_currentRD;
+
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to collect channel list; "
+ "regdomain likely %u country code %u\n",
+ __func__, rd, CTRY_DEFAULT);
+ return -EINVAL;
+ }
+
+ band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ];
+ band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ];
+ chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ];
+ chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ];
+
+ for (i = 0; i < nchan; i++) {
+ c = &ah->ah_channels[i];
+ if (IS_CHAN_2GHZ(c)) {
+ chan_2ghz[a].band = IEEE80211_BAND_2GHZ;
+ chan_2ghz[a].center_freq = c->channel;
+ chan_2ghz[a].max_power = c->maxTxPower;
+
+ if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
+ chan_2ghz[a].flags |=
+ IEEE80211_CHAN_NO_IBSS;
+ if (c->channelFlags & CHANNEL_PASSIVE)
+ chan_2ghz[a].flags |=
+ IEEE80211_CHAN_PASSIVE_SCAN;
+
+ band_2ghz->n_channels = ++a;
+
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: 2MHz channel: %d, "
+ "channelFlags: 0x%x\n",
+ __func__,
+ c->channel,
+ c->channelFlags);
+ } else if (IS_CHAN_5GHZ(c)) {
+ chan_5ghz[b].band = IEEE80211_BAND_5GHZ;
+ chan_5ghz[b].center_freq = c->channel;
+ chan_5ghz[b].max_power = c->maxTxPower;
+
+ if (c->privFlags & CHANNEL_DISALLOW_ADHOC)
+ chan_5ghz[b].flags |=
+ IEEE80211_CHAN_NO_IBSS;
+ if (c->channelFlags & CHANNEL_PASSIVE)
+ chan_5ghz[b].flags |=
+ IEEE80211_CHAN_PASSIVE_SCAN;
+
+ band_5ghz->n_channels = ++b;
+
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: 5MHz channel: %d, "
+ "channelFlags: 0x%x\n",
+ __func__,
+ c->channel,
+ c->channelFlags);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Determine mode from channel flags
+ *
+ * This routine will provide the enumerated WIRELESSS_MODE value based
+ * on the settings of the channel flags. If ho valid set of flags
+ * exist, the lowest mode (11b) is selected.
+*/
+
+static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan)
+{
+ if (chan->chanmode == CHANNEL_A)
+ return ATH9K_MODE_11A;
+ else if (chan->chanmode == CHANNEL_G)
+ return ATH9K_MODE_11G;
+ else if (chan->chanmode == CHANNEL_B)
+ return ATH9K_MODE_11B;
+ else if (chan->chanmode == CHANNEL_A_HT20)
+ return ATH9K_MODE_11NA_HT20;
+ else if (chan->chanmode == CHANNEL_G_HT20)
+ return ATH9K_MODE_11NG_HT20;
+ else if (chan->chanmode == CHANNEL_A_HT40PLUS)
+ return ATH9K_MODE_11NA_HT40PLUS;
+ else if (chan->chanmode == CHANNEL_A_HT40MINUS)
+ return ATH9K_MODE_11NA_HT40MINUS;
+ else if (chan->chanmode == CHANNEL_G_HT40PLUS)
+ return ATH9K_MODE_11NG_HT40PLUS;
+ else if (chan->chanmode == CHANNEL_G_HT40MINUS)
+ return ATH9K_MODE_11NG_HT40MINUS;
+
+ /* NB: should not get here */
+ return ATH9K_MODE_11B;
+}
+
+/*
+ * Stop the device, grabbing the top-level lock to protect
+ * against concurrent entry through ath_init (which can happen
+ * if another thread does a system call and the thread doing the
+ * stop is preempted).
+ */
+
+static int ath_stop(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %u\n",
+ __func__, sc->sc_invalid);
+
+ /*
+ * Shutdown the hardware and driver:
+ * stop output from above
+ * reset 802.11 state machine
+ * (sends station deassoc/deauth frames)
+ * turn off timers
+ * disable interrupts
+ * clear transmit machinery
+ * clear receive machinery
+ * turn off the radio
+ * reclaim beacon resources
+ *
+ * Note that some of this work is not possible if the
+ * hardware is gone (invalid).
+ */
+
+ if (!sc->sc_invalid)
+ ath9k_hw_set_interrupts(ah, 0);
+ ath_draintxq(sc, false);
+ if (!sc->sc_invalid) {
+ ath_stoprecv(sc);
+ ath9k_hw_phy_disable(ah);
+ } else
+ sc->sc_rxlink = NULL;
+
+ return 0;
+}
+
+/*
+ * Start Scan
+ *
+ * This function is called when starting a channel scan. It will perform
+ * power save wakeup processing, set the filter for the scan, and get the
+ * chip ready to send broadcast packets out during the scan.
+*/
+
+void ath_scan_start(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ u32 rfilt;
+ u32 now = (u32) jiffies_to_msecs(get_timestamp());
+
+ sc->sc_scanning = 1;
+ rfilt = ath_calcrxfilter(sc);
+ ath9k_hw_setrxfilter(ah, rfilt);
+ ath9k_hw_write_associd(ah, ath_bcast_mac, 0);
+
+ /* Restore previous power management state. */
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0\n",
+ now / 1000, now % 1000, __func__, rfilt);
+}
+
+/*
+ * Scan End
+ *
+ * This routine is called by the upper layer when the scan is completed. This
+ * will set the filters back to normal operating mode, set the BSSID to the
+ * correct value, and restore the power save state.
+*/
+
+void ath_scan_end(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ u32 rfilt;
+ u32 now = (u32) jiffies_to_msecs(get_timestamp());
+
+ sc->sc_scanning = 0;
+ /* Request for a full reset due to rx packet filter changes */
+ sc->sc_full_reset = 1;
+ rfilt = ath_calcrxfilter(sc);
+ ath9k_hw_setrxfilter(ah, rfilt);
+ ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid);
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%d.%03d | %s: RX filter 0x%x aid 0x%x\n",
+ now / 1000, now % 1000, __func__, rfilt, sc->sc_curaid);
+}
+
+/*
+ * Set the current channel
+ *
+ * Set/change channels. If the channel is really being changed, it's done
+ * by reseting the chip. To accomplish this we must first cleanup any pending
+ * DMA, then restart stuff after a la ath_init.
+*/
+int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ bool fastcc = true, stopped;
+ enum ath9k_ht_macmode ht_macmode;
+
+ if (sc->sc_invalid) /* if the device is invalid or removed */
+ return -EIO;
+
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n",
+ __func__,
+ ath9k_hw_mhz2ieee(ah, sc->sc_curchan.channel,
+ sc->sc_curchan.channelFlags),
+ sc->sc_curchan.channel,
+ ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags),
+ hchan->channel, hchan->channelFlags);
+
+ ht_macmode = ath_cwm_macmode(sc);
+
+ if (hchan->channel != sc->sc_curchan.channel ||
+ hchan->channelFlags != sc->sc_curchan.channelFlags ||
+ sc->sc_update_chainmask || sc->sc_full_reset) {
+ int status;
+ /*
+ * This is only performed if the channel settings have
+ * actually changed.
+ *
+ * To switch channels clear any pending DMA operations;
+ * wait long enough for the RX fifo to drain, reset the
+ * hardware at the new frequency, and then re-enable
+ * the relevant bits of the h/w.
+ */
+ ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */
+ ath_draintxq(sc, false); /* clear pending tx frames */
+ stopped = ath_stoprecv(sc); /* turn off frame recv */
+
+ /* XXX: do not flush receive queue here. We don't want
+ * to flush data frames already in queue because of
+ * changing channel. */
+
+ if (!stopped || sc->sc_full_reset)
+ fastcc = false;
+
+ spin_lock_bh(&sc->sc_resetlock);
+ if (!ath9k_hw_reset(ah, sc->sc_opmode, hchan,
+ ht_macmode, sc->sc_tx_chainmask,
+ sc->sc_rx_chainmask,
+ sc->sc_ht_extprotspacing,
+ fastcc, &status)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to reset channel %u (%uMhz) "
+ "flags 0x%x hal status %u\n", __func__,
+ ath9k_hw_mhz2ieee(ah, hchan->channel,
+ hchan->channelFlags),
+ hchan->channel, hchan->channelFlags, status);
+ spin_unlock_bh(&sc->sc_resetlock);
+ return -EIO;
+ }
+ spin_unlock_bh(&sc->sc_resetlock);
+
+ sc->sc_curchan = *hchan;
+ sc->sc_update_chainmask = 0;
+ sc->sc_full_reset = 0;
+
+ /* Re-enable rx framework */
+ if (ath_startrecv(sc) != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to restart recv logic\n", __func__);
+ return -EIO;
+ }
+ /*
+ * Change channels and update the h/w rate map
+ * if we're switching; e.g. 11a to 11b/g.
+ */
+ ath_setcurmode(sc, ath_chan2mode(hchan));
+
+ ath_update_txpow(sc); /* update tx power state */
+ /*
+ * Re-enable interrupts.
+ */
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+ }
+ return 0;
+}
+
+/**********************/
+/* Chainmask Handling */
+/**********************/
+
+static void ath_chainmask_sel_timertimeout(unsigned long data)
+{
+ struct ath_chainmask_sel *cm = (struct ath_chainmask_sel *)data;
+ cm->switch_allowed = 1;
+}
+
+/* Start chainmask select timer */
+static void ath_chainmask_sel_timerstart(struct ath_chainmask_sel *cm)
+{
+ cm->switch_allowed = 0;
+ mod_timer(&cm->timer, ath_chainmask_sel_period);
+}
+
+/* Stop chainmask select timer */
+static void ath_chainmask_sel_timerstop(struct ath_chainmask_sel *cm)
+{
+ cm->switch_allowed = 0;
+ del_timer_sync(&cm->timer);
+}
+
+static void ath_chainmask_sel_init(struct ath_softc *sc, struct ath_node *an)
+{
+ struct ath_chainmask_sel *cm = &an->an_chainmask_sel;
+
+ memzero(cm, sizeof(struct ath_chainmask_sel));
+
+ cm->cur_tx_mask = sc->sc_tx_chainmask;
+ cm->cur_rx_mask = sc->sc_rx_chainmask;
+ cm->tx_avgrssi = ATH_RSSI_DUMMY_MARKER;
+ setup_timer(&cm->timer,
+ ath_chainmask_sel_timertimeout, (unsigned long) cm);
+}
+
+int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an)
+{
+ struct ath_chainmask_sel *cm = &an->an_chainmask_sel;
+
+ /*
+ * Disable auto-swtiching in one of the following if conditions.
+ * sc_chainmask_auto_sel is used for internal global auto-switching
+ * enabled/disabled setting
+ */
+ if (sc->sc_ah->ah_caps.tx_chainmask != ATH_CHAINMASK_SEL_3X3) {
+ cm->cur_tx_mask = sc->sc_tx_chainmask;
+ return cm->cur_tx_mask;
+ }
+
+ if (cm->tx_avgrssi == ATH_RSSI_DUMMY_MARKER)
+ return cm->cur_tx_mask;
+
+ if (cm->switch_allowed) {
+ /* Switch down from tx 3 to tx 2. */
+ if (cm->cur_tx_mask == ATH_CHAINMASK_SEL_3X3 &&
+ ATH_RSSI_OUT(cm->tx_avgrssi) >=
+ ath_chainmask_sel_down_rssi_thres) {
+ cm->cur_tx_mask = sc->sc_tx_chainmask;
+
+ /* Don't let another switch happen until
+ * this timer expires */
+ ath_chainmask_sel_timerstart(cm);
+ }
+ /* Switch up from tx 2 to 3. */
+ else if (cm->cur_tx_mask == sc->sc_tx_chainmask &&
+ ATH_RSSI_OUT(cm->tx_avgrssi) <=
+ ath_chainmask_sel_up_rssi_thres) {
+ cm->cur_tx_mask = ATH_CHAINMASK_SEL_3X3;
+
+ /* Don't let another switch happen
+ * until this timer expires */
+ ath_chainmask_sel_timerstart(cm);
+ }
+ }
+
+ return cm->cur_tx_mask;
+}
+
+/*
+ * Update tx/rx chainmask. For legacy association,
+ * hard code chainmask to 1x1, for 11n association, use
+ * the chainmask configuration.
+ */
+
+void ath_update_chainmask(struct ath_softc *sc, int is_ht)
+{
+ sc->sc_update_chainmask = 1;
+ if (is_ht) {
+ sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask;
+ sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask;
+ } else {
+ sc->sc_tx_chainmask = 1;
+ sc->sc_rx_chainmask = 1;
+ }
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: tx chmask: %d, rx chmask: %d\n",
+ __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask);
+}
+
+/******************/
+/* VAP management */
+/******************/
+
+/*
+ * VAP in Listen mode
+ *
+ * This routine brings the VAP out of the down state into a "listen" state
+ * where it waits for association requests. This is used in AP and AdHoc
+ * modes.
+*/
+
+int ath_vap_listen(struct ath_softc *sc, int if_id)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_vap *avp;
+ u32 rfilt = 0;
+ DECLARE_MAC_BUF(mac);
+
+ avp = sc->sc_vaps[if_id];
+ if (avp == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n",
+ __func__, if_id);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_SLOW_ANT_DIV
+ ath_slow_ant_div_stop(&sc->sc_antdiv);
+#endif
+
+ /* update ratectrl about the new state */
+ ath_rate_newstate(sc, avp);
+
+ rfilt = ath_calcrxfilter(sc);
+ ath9k_hw_setrxfilter(ah, rfilt);
+
+ if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS) {
+ memcpy(sc->sc_curbssid, ath_bcast_mac, ETH_ALEN);
+ ath9k_hw_write_associd(ah, sc->sc_curbssid, sc->sc_curaid);
+ } else
+ sc->sc_curaid = 0;
+
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: RX filter 0x%x bssid %s aid 0x%x\n",
+ __func__, rfilt, print_mac(mac,
+ sc->sc_curbssid), sc->sc_curaid);
+
+ /*
+ * XXXX
+ * Disable BMISS interrupt when we're not associated
+ */
+ ath9k_hw_set_interrupts(ah,
+ sc->sc_imask & ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
+ sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+ /* need to reconfigure the beacons when it moves to RUN */
+ sc->sc_beacons = 0;
+
+ return 0;
+}
+
+int ath_vap_attach(struct ath_softc *sc,
+ int if_id,
+ struct ieee80211_vif *if_data,
+ enum ath9k_opmode opmode)
+{
+ struct ath_vap *avp;
+
+ if (if_id >= ATH_BCBUF || sc->sc_vaps[if_id] != NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Invalid interface id = %u\n", __func__, if_id);
+ return -EINVAL;
+ }
+
+ switch (opmode) {
+ case ATH9K_M_STA:
+ case ATH9K_M_IBSS:
+ case ATH9K_M_MONITOR:
+ break;
+ case ATH9K_M_HOSTAP:
+ /* XXX not right, beacon buffer is allocated on RUN trans */
+ if (list_empty(&sc->sc_bbuf))
+ return -ENOMEM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* create ath_vap */
+ avp = kmalloc(sizeof(struct ath_vap), GFP_KERNEL);
+ if (avp == NULL)
+ return -ENOMEM;
+
+ memzero(avp, sizeof(struct ath_vap));
+ avp->av_if_data = if_data;
+ /* Set the VAP opmode */
+ avp->av_opmode = opmode;
+ avp->av_bslot = -1;
+ INIT_LIST_HEAD(&avp->av_mcastq.axq_q);
+ INIT_LIST_HEAD(&avp->av_mcastq.axq_acq);
+ spin_lock_init(&avp->av_mcastq.axq_lock);
+
+ ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
+
+ sc->sc_vaps[if_id] = avp;
+ sc->sc_nvaps++;
+ /* Set the device opmode */
+ sc->sc_opmode = opmode;
+
+ /* default VAP configuration */
+ avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE;
+ avp->av_config.av_fixed_retryset = 0x03030303;
+
+ return 0;
+}
+
+int ath_vap_detach(struct ath_softc *sc, int if_id)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_vap *avp;
+
+ avp = sc->sc_vaps[if_id];
+ if (avp == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n",
+ __func__, if_id);
+ return -EINVAL;
+ }
+
+ /*
+ * Quiesce the hardware while we remove the vap. In
+ * particular we need to reclaim all references to the
+ * vap state by any frames pending on the tx queues.
+ *
+ * XXX can we do this w/o affecting other vap's?
+ */
+ ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */
+ ath_draintxq(sc, false); /* stop xmit side */
+ ath_stoprecv(sc); /* stop recv side */
+ ath_flushrecv(sc); /* flush recv queue */
+
+ /* Reclaim any pending mcast bufs on the vap. */
+ ath_tx_draintxq(sc, &avp->av_mcastq, false);
+
+ kfree(avp);
+ sc->sc_vaps[if_id] = NULL;
+ sc->sc_nvaps--;
+
+ return 0;
+}
+
+int ath_vap_config(struct ath_softc *sc,
+ int if_id, struct ath_vap_config *if_config)
+{
+ struct ath_vap *avp;
+
+ if (if_id >= ATH_BCBUF) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Invalid interface id = %u\n", __func__, if_id);
+ return -EINVAL;
+ }
+
+ avp = sc->sc_vaps[if_id];
+ ASSERT(avp != NULL);
+
+ if (avp)
+ memcpy(&avp->av_config, if_config, sizeof(avp->av_config));
+
+ return 0;
+}
+
+/********/
+/* Core */
+/********/
+
+int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int status;
+ int error = 0;
+ enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc);
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", __func__, sc->sc_opmode);
+
+ /*
+ * Stop anything previously setup. This is safe
+ * whether this is the first time through or not.
+ */
+ ath_stop(sc);
+
+ /* Initialize chanmask selection */
+ sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
+ sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
+
+ /* Reset SERDES registers */
+ ath9k_hw_configpcipowersave(ah, 0);
+
+ /*
+ * The basic interface to setting the hardware in a good
+ * state is ``reset''. On return the hardware is known to
+ * be powered up and with interrupts disabled. This must
+ * be followed by initialization of the appropriate bits
+ * and then setup of the interrupt mask.
+ */
+ sc->sc_curchan = *initial_chan;
+
+ spin_lock_bh(&sc->sc_resetlock);
+ if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan, ht_macmode,
+ sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+ sc->sc_ht_extprotspacing, false, &status)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to reset hardware; hal status %u "
+ "(freq %u flags 0x%x)\n", __func__, status,
+ sc->sc_curchan.channel, sc->sc_curchan.channelFlags);
+ error = -EIO;
+ spin_unlock_bh(&sc->sc_resetlock);
+ goto done;
+ }
+ spin_unlock_bh(&sc->sc_resetlock);
+ /*
+ * This is needed only to setup initial state
+ * but it's best done after a reset.
+ */
+ ath_update_txpow(sc);
+
+ /*
+ * Setup the hardware after reset:
+ * The receive engine is set going.
+ * Frame transmit is handled entirely
+ * in the frame output path; there's nothing to do
+ * here except setup the interrupt mask.
+ */
+ if (ath_startrecv(sc) != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to start recv logic\n", __func__);
+ error = -EIO;
+ goto done;
+ }
+ /* Setup our intr mask. */
+ sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX
+ | ATH9K_INT_RXEOL | ATH9K_INT_RXORN
+ | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
+
+ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT)
+ sc->sc_imask |= ATH9K_INT_GTT;
+
+ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
+ sc->sc_imask |= ATH9K_INT_CST;
+
+ /*
+ * Enable MIB interrupts when there are hardware phy counters.
+ * Note we only do this (at the moment) for station mode.
+ */
+ if (ath9k_hw_phycounters(ah) &&
+ ((sc->sc_opmode == ATH9K_M_STA) || (sc->sc_opmode == ATH9K_M_IBSS)))
+ sc->sc_imask |= ATH9K_INT_MIB;
+ /*
+ * Some hardware processes the TIM IE and fires an
+ * interrupt when the TIM bit is set. For hardware
+ * that does, if not overridden by configuration,
+ * enable the TIM interrupt when operating as station.
+ */
+ if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) &&
+ (sc->sc_opmode == ATH9K_M_STA) &&
+ !sc->sc_config.swBeaconProcess)
+ sc->sc_imask |= ATH9K_INT_TIM;
+ /*
+ * Don't enable interrupts here as we've not yet built our
+ * vap and node data structures, which will be needed as soon
+ * as we start receiving.
+ */
+ ath_setcurmode(sc, ath_chan2mode(initial_chan));
+
+ /* XXX: we must make sure h/w is ready and clear invalid flag
+ * before turning on interrupt. */
+ sc->sc_invalid = 0;
+done:
+ return error;
+}
+
+/*
+ * Reset the hardware w/o losing operational state. This is
+ * basically a more efficient way of doing ath_stop, ath_init,
+ * followed by state transitions to the current 802.11
+ * operational state. Used to recover from errors rx overrun
+ * and to reset the hardware when rf gain settings must be reset.
+ */
+
+static int ath_reset_start(struct ath_softc *sc, u32 flag)
+{
+ struct ath_hal *ah = sc->sc_ah;
+
+ ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */
+ ath_draintxq(sc, flag & RESET_RETRY_TXQ); /* stop xmit side */
+ ath_stoprecv(sc); /* stop recv side */
+ ath_flushrecv(sc); /* flush recv queue */
+
+ return 0;
+}
+
+static int ath_reset_end(struct ath_softc *sc, u32 flag)
+{
+ struct ath_hal *ah = sc->sc_ah;
+
+ if (ath_startrecv(sc) != 0) /* restart recv */
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to start recv logic\n", __func__);
+
+ /*
+ * We may be doing a reset in response to a request
+ * that changes the channel so update any state that
+ * might change as a result.
+ */
+ ath_setcurmode(sc, ath_chan2mode(&sc->sc_curchan));
+
+ ath_update_txpow(sc); /* update tx power state */
+
+ if (sc->sc_beacons)
+ ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+
+ /* Restart the txq */
+ if (flag & RESET_RETRY_TXQ) {
+ int i;
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i)) {
+ spin_lock_bh(&sc->sc_txq[i].axq_lock);
+ ath_txq_schedule(sc, &sc->sc_txq[i]);
+ spin_unlock_bh(&sc->sc_txq[i].axq_lock);
+ }
+ }
+ }
+ return 0;
+}
+
+int ath_reset(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int status;
+ int error = 0;
+ enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc);
+
+ /* NB: indicate channel change so we do a full reset */
+ spin_lock_bh(&sc->sc_resetlock);
+ if (!ath9k_hw_reset(ah, sc->sc_opmode, &sc->sc_curchan,
+ ht_macmode,
+ sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+ sc->sc_ht_extprotspacing, false, &status)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to reset hardware; hal status %u\n",
+ __func__, status);
+ error = -EIO;
+ }
+ spin_unlock_bh(&sc->sc_resetlock);
+
+ return error;
+}
+
+int ath_suspend(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+
+ /* No I/O if device has been surprise removed */
+ if (sc->sc_invalid)
+ return -EIO;
+
+ /* Shut off the interrupt before setting sc->sc_invalid to '1' */
+ ath9k_hw_set_interrupts(ah, 0);
+
+ /* XXX: we must make sure h/w will not generate any interrupt
+ * before setting the invalid flag. */
+ sc->sc_invalid = 1;
+
+ /* disable HAL and put h/w to sleep */
+ ath9k_hw_disable(sc->sc_ah);
+
+ ath9k_hw_configpcipowersave(sc->sc_ah, 1);
+
+ return 0;
+}
+
+/* Interrupt handler. Most of the actual processing is deferred.
+ * It's the caller's responsibility to ensure the chip is awake. */
+
+irqreturn_t ath_isr(int irq, void *dev)
+{
+ struct ath_softc *sc = dev;
+ struct ath_hal *ah = sc->sc_ah;
+ enum ath9k_int status;
+ bool sched = false;
+
+ do {
+ if (sc->sc_invalid) {
+ /*
+ * The hardware is not ready/present, don't
+ * touch anything. Note this can happen early
+ * on if the IRQ is shared.
+ */
+ return IRQ_NONE;
+ }
+ if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */
+ return IRQ_NONE;
+ }
+
+ /*
+ * Figure out the reason(s) for the interrupt. Note
+ * that the hal returns a pseudo-ISR that may include
+ * bits we haven't explicitly enabled so we mask the
+ * value to insure we only process bits we requested.
+ */
+ ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */
+
+ status &= sc->sc_imask; /* discard unasked-for bits */
+
+ /*
+ * If there are no status bits set, then this interrupt was not
+ * for me (should have been caught above).
+ */
+
+ if (!status)
+ return IRQ_NONE;
+
+ sc->sc_intrstatus = status;
+
+ if (status & ATH9K_INT_FATAL) {
+ /* need a chip reset */
+ sched = true;
+ } else if (status & ATH9K_INT_RXORN) {
+ /* need a chip reset */
+ sched = true;
+ } else {
+ if (status & ATH9K_INT_SWBA) {
+ /* schedule a tasklet for beacon handling */
+ tasklet_schedule(&sc->bcon_tasklet);
+ }
+ if (status & ATH9K_INT_RXEOL) {
+ /*
+ * NB: the hardware should re-read the link when
+ * RXE bit is written, but it doesn't work
+ * at least on older hardware revs.
+ */
+ sched = true;
+ }
+
+ if (status & ATH9K_INT_TXURN)
+ /* bump tx trigger level */
+ ath9k_hw_updatetxtriglevel(ah, true);
+ /* XXX: optimize this */
+ if (status & ATH9K_INT_RX)
+ sched = true;
+ if (status & ATH9K_INT_TX)
+ sched = true;
+ if (status & ATH9K_INT_BMISS)
+ sched = true;
+ /* carrier sense timeout */
+ if (status & ATH9K_INT_CST)
+ sched = true;
+ if (status & ATH9K_INT_MIB) {
+ /*
+ * Disable interrupts until we service the MIB
+ * interrupt; otherwise it will continue to
+ * fire.
+ */
+ ath9k_hw_set_interrupts(ah, 0);
+ /*
+ * Let the hal handle the event. We assume
+ * it will clear whatever condition caused
+ * the interrupt.
+ */
+ ath9k_hw_procmibevent(ah, &sc->sc_halstats);
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+ }
+ if (status & ATH9K_INT_TIM_TIMER) {
+ if (!(ah->ah_caps.hw_caps &
+ ATH9K_HW_CAP_AUTOSLEEP)) {
+ /* Clear RxAbort bit so that we can
+ * receive frames */
+ ath9k_hw_setrxabort(ah, 0);
+ sched = true;
+ }
+ }
+ }
+ } while (0);
+
+ if (sched) {
+ /* turn off every interrupt except SWBA */
+ ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA));
+ tasklet_schedule(&sc->intr_tq);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* Deferred interrupt processing */
+
+static void ath9k_tasklet(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *)data;
+ u32 status = sc->sc_intrstatus;
+
+ if (status & ATH9K_INT_FATAL) {
+ /* need a chip reset */
+ ath_internal_reset(sc);
+ return;
+ } else {
+
+ if (status &
+ (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
+ /* XXX: fill me in */
+ /*
+ if (status & ATH9K_INT_RXORN) {
+ }
+ if (status & ATH9K_INT_RXEOL) {
+ }
+ */
+ spin_lock_bh(&sc->sc_rxflushlock);
+ ath_rx_tasklet(sc, 0);
+ spin_unlock_bh(&sc->sc_rxflushlock);
+ }
+ /* XXX: optimize this */
+ if (status & ATH9K_INT_TX)
+ ath_tx_tasklet(sc);
+ /* XXX: fill me in */
+ /*
+ if (status & ATH9K_INT_BMISS) {
+ }
+ if (status & (ATH9K_INT_TIM | ATH9K_INT_DTIMSYNC)) {
+ if (status & ATH9K_INT_TIM) {
+ }
+ if (status & ATH9K_INT_DTIMSYNC) {
+ }
+ }
+ */
+ }
+
+ /* re-enable hardware interrupt */
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
+}
+
+int ath_init(u16 devid, struct ath_softc *sc)
+{
+ struct ath_hal *ah = NULL;
+ int status;
+ int error = 0, i;
+ int csz = 0;
+ u32 rd;
+
+ /* XXX: hardware will not be ready until ath_open() being called */
+ sc->sc_invalid = 1;
+
+ sc->sc_debug = DBG_DEFAULT;
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid);
+
+ /* Initialize tasklet */
+ tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
+ tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
+ (unsigned long)sc);
+
+ /*
+ * Cache line size is used to size and align various
+ * structures used to communicate with the hardware.
+ */
+ bus_read_cachesize(sc, &csz);
+ /* XXX assert csz is non-zero */
+ sc->sc_cachelsz = csz << 2; /* convert to bytes */
+
+ spin_lock_init(&sc->sc_resetlock);
+
+ ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
+ if (ah == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to attach hardware; HAL status %u\n",
+ __func__, status);
+ error = -ENXIO;
+ goto bad;
+ }
+ sc->sc_ah = ah;
+
+ /* Get the chipset-specific aggr limit. */
+ sc->sc_rtsaggrlimit = ah->ah_caps.rts_aggr_limit;
+
+ /* Get the hardware key cache size. */
+ sc->sc_keymax = ah->ah_caps.keycache_size;
+ if (sc->sc_keymax > ATH_KEYMAX) {
+ DPRINTF(sc, ATH_DBG_KEYCACHE,
+ "%s: Warning, using only %u entries in %u key cache\n",
+ __func__, ATH_KEYMAX, sc->sc_keymax);
+ sc->sc_keymax = ATH_KEYMAX;
+ }
+
+ /*
+ * Reset the key cache since some parts do not
+ * reset the contents on initial power up.
+ */
+ for (i = 0; i < sc->sc_keymax; i++)
+ ath9k_hw_keyreset(ah, (u16) i);
+ /*
+ * Mark key cache slots associated with global keys
+ * as in use. If we knew TKIP was not to be used we
+ * could leave the +32, +64, and +32+64 slots free.
+ * XXX only for splitmic.
+ */
+ for (i = 0; i < IEEE80211_WEP_NKID; i++) {
+ set_bit(i, sc->sc_keymap);
+ set_bit(i + 32, sc->sc_keymap);
+ set_bit(i + 64, sc->sc_keymap);
+ set_bit(i + 32 + 64, sc->sc_keymap);
+ }
+ /*
+ * Collect the channel list using the default country
+ * code and including outdoor channels. The 802.11 layer
+ * is resposible for filtering this list based on settings
+ * like the phy mode.
+ */
+ rd = ah->ah_currentRD;
+
+ error = ath_setup_channels(sc);
+ if (error)
+ goto bad;
+
+ /* default to STA mode */
+ sc->sc_opmode = ATH9K_M_MONITOR;
+
+ /* Setup rate tables */
+
+ ath_setup_rates(sc, IEEE80211_BAND_2GHZ);
+ ath_setup_rates(sc, IEEE80211_BAND_5GHZ);
+
+ /* NB: setup here so ath_rate_update is happy */
+ ath_setcurmode(sc, ATH9K_MODE_11A);
+
+ /*
+ * Allocate hardware transmit queues: one queue for
+ * beacon frames and one data queue for each QoS
+ * priority. Note that the hal handles reseting
+ * these queues at the needed time.
+ */
+ sc->sc_bhalq = ath_beaconq_setup(ah);
+ if (sc->sc_bhalq == -1) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup a beacon xmit queue\n", __func__);
+ error = -EIO;
+ goto bad2;
+ }
+ sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
+ if (sc->sc_cabq == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup CAB xmit queue\n", __func__);
+ error = -EIO;
+ goto bad2;
+ }
+
+ sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME;
+ ath_cabq_update(sc);
+
+ for (i = 0; i < ARRAY_SIZE(sc->sc_haltype2q); i++)
+ sc->sc_haltype2q[i] = -1;
+
+ /* Setup data queues */
+ /* NB: ensure BK queue is the lowest priority h/w queue */
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup xmit queue for BK traffic\n",
+ __func__);
+ error = -EIO;
+ goto bad2;
+ }
+
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup xmit queue for BE traffic\n",
+ __func__);
+ error = -EIO;
+ goto bad2;
+ }
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup xmit queue for VI traffic\n",
+ __func__);
+ error = -EIO;
+ goto bad2;
+ }
+ if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to setup xmit queue for VO traffic\n",
+ __func__);
+ error = -EIO;
+ goto bad2;
+ }
+
+ sc->sc_rc = ath_rate_attach(ah);
+ if (sc->sc_rc == NULL) {
+ error = EIO;
+ goto bad2;
+ }
+
+ if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_TKIP, NULL)) {
+ /*
+ * Whether we should enable h/w TKIP MIC.
+ * XXX: if we don't support WME TKIP MIC, then we wouldn't
+ * report WMM capable, so it's always safe to turn on
+ * TKIP MIC in this case.
+ */
+ ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC,
+ 0, 1, NULL);
+ }
+
+ /*
+ * Check whether the separate key cache entries
+ * are required to handle both tx+rx MIC keys.
+ * With split mic keys the number of stations is limited
+ * to 27 otherwise 59.
+ */
+ if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_TKIP, NULL)
+ && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER,
+ ATH9K_CIPHER_MIC, NULL)
+ && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT,
+ 0, NULL))
+ sc->sc_splitmic = 1;
+
+ /* turn on mcast key search if possible */
+ if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
+ (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1,
+ 1, NULL);
+
+ sc->sc_config.txpowlimit = ATH_TXPOWER_MAX;
+ sc->sc_config.txpowlimit_override = 0;
+
+ /* 11n Capabilities */
+ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
+ sc->sc_txaggr = 1;
+ sc->sc_rxaggr = 1;
+ }
+
+ sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask;
+ sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask;
+
+ /* Configuration for rx chain detection */
+ sc->sc_rxchaindetect_ref = 0;
+ sc->sc_rxchaindetect_thresh5GHz = 35;
+ sc->sc_rxchaindetect_thresh2GHz = 35;
+ sc->sc_rxchaindetect_delta5GHz = 30;
+ sc->sc_rxchaindetect_delta2GHz = 30;
+
+ ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
+ sc->sc_defant = ath9k_hw_getdefantenna(ah);
+
+ ath9k_hw_getmac(ah, sc->sc_myaddr);
+ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) {
+ ath9k_hw_getbssidmask(ah, sc->sc_bssidmask);
+ ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask);
+ ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
+ }
+ sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */
+
+ /* initialize beacon slots */
+ for (i = 0; i < ARRAY_SIZE(sc->sc_bslot); i++)
+ sc->sc_bslot[i] = ATH_IF_ID_ANY;
+
+ /* save MISC configurations */
+ sc->sc_config.swBeaconProcess = 1;
+
+#ifdef CONFIG_SLOW_ANT_DIV
+ /* range is 40 - 255, we use something in the middle */
+ ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127);
+#endif
+
+ return 0;
+bad2:
+ /* cleanup tx queues */
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_cleanupq(sc, &sc->sc_txq[i]);
+bad:
+ if (ah)
+ ath9k_hw_detach(ah);
+ return error;
+}
+
+void ath_deinit(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int i;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__);
+
+ ath_stop(sc);
+ if (!sc->sc_invalid)
+ ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
+ ath_rate_detach(sc->sc_rc);
+ /* cleanup tx queues */
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_cleanupq(sc, &sc->sc_txq[i]);
+ ath9k_hw_detach(ah);
+}
+
+/*******************/
+/* Node Management */
+/*******************/
+
+struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id)
+{
+ struct ath_vap *avp;
+ struct ath_node *an;
+ DECLARE_MAC_BUF(mac);
+
+ avp = sc->sc_vaps[if_id];
+ ASSERT(avp != NULL);
+
+ /* mac80211 sta_notify callback is from an IRQ context, so no sleep */
+ an = kmalloc(sizeof(struct ath_node), GFP_ATOMIC);
+ if (an == NULL)
+ return NULL;
+ memzero(an, sizeof(*an));
+
+ an->an_sc = sc;
+ memcpy(an->an_addr, addr, ETH_ALEN);
+ atomic_set(&an->an_refcnt, 1);
+
+ /* set up per-node tx/rx state */
+ ath_tx_node_init(sc, an);
+ ath_rx_node_init(sc, an);
+
+ ath_chainmask_sel_init(sc, an);
+ ath_chainmask_sel_timerstart(&an->an_chainmask_sel);
+ list_add(&an->list, &sc->node_list);
+
+ return an;
+}
+
+void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag)
+{
+ unsigned long flags;
+
+ DECLARE_MAC_BUF(mac);
+
+ ath_chainmask_sel_timerstop(&an->an_chainmask_sel);
+ an->an_flags |= ATH_NODE_CLEAN;
+ ath_tx_node_cleanup(sc, an, bh_flag);
+ ath_rx_node_cleanup(sc, an);
+
+ ath_tx_node_free(sc, an);
+ ath_rx_node_free(sc, an);
+
+ spin_lock_irqsave(&sc->node_lock, flags);
+
+ list_del(&an->list);
+
+ spin_unlock_irqrestore(&sc->node_lock, flags);
+
+ kfree(an);
+}
+
+/* Finds a node and increases the refcnt if found */
+
+struct ath_node *ath_node_get(struct ath_softc *sc, u8 *addr)
+{
+ struct ath_node *an = NULL, *an_found = NULL;
+
+ if (list_empty(&sc->node_list)) /* FIXME */
+ goto out;
+ list_for_each_entry(an, &sc->node_list, list) {
+ if (!compare_ether_addr(an->an_addr, addr)) {
+ atomic_inc(&an->an_refcnt);
+ an_found = an;
+ break;
+ }
+ }
+out:
+ return an_found;
+}
+
+/* Decrements the refcnt and if it drops to zero, detach the node */
+
+void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag)
+{
+ if (atomic_dec_and_test(&an->an_refcnt))
+ ath_node_detach(sc, an, bh_flag);
+}
+
+/* Finds a node, doesn't increment refcnt. Caller must hold sc->node_lock */
+struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr)
+{
+ struct ath_node *an = NULL, *an_found = NULL;
+
+ if (list_empty(&sc->node_list))
+ return NULL;
+
+ list_for_each_entry(an, &sc->node_list, list)
+ if (!compare_ether_addr(an->an_addr, addr)) {
+ an_found = an;
+ break;
+ }
+
+ return an_found;
+}
+
+/*
+ * Set up New Node
+ *
+ * Setup driver-specific state for a newly associated node. This routine
+ * really only applies if compression or XR are enabled, there is no code
+ * covering any other cases.
+*/
+
+void ath_newassoc(struct ath_softc *sc,
+ struct ath_node *an, int isnew, int isuapsd)
+{
+ int tidno;
+
+ /* if station reassociates, tear down the aggregation state. */
+ if (!isnew) {
+ for (tidno = 0; tidno < WME_NUM_TID; tidno++) {
+ if (sc->sc_txaggr)
+ ath_tx_aggr_teardown(sc, an, tidno);
+ if (sc->sc_rxaggr)
+ ath_rx_aggr_teardown(sc, an, tidno);
+ }
+ }
+ an->an_flags = 0;
+}
+
+/**************/
+/* Encryption */
+/**************/
+
+void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot)
+{
+ ath9k_hw_keyreset(sc->sc_ah, keyix);
+ if (freeslot)
+ clear_bit(keyix, sc->sc_keymap);
+}
+
+int ath_keyset(struct ath_softc *sc,
+ u16 keyix,
+ struct ath9k_keyval *hk,
+ const u8 mac[ETH_ALEN])
+{
+ bool status;
+
+ status = ath9k_hw_set_keycache_entry(sc->sc_ah,
+ keyix, hk, mac, false);
+
+ return status != false;
+}
+
+/***********************/
+/* TX Power/Regulatory */
+/***********************/
+
+/*
+ * Set Transmit power in HAL
+ *
+ * This routine makes the actual HAL calls to set the new transmit power
+ * limit.
+*/
+
+void ath_update_txpow(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ u32 txpow;
+
+ if (sc->sc_curtxpow != sc->sc_config.txpowlimit) {
+ ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit);
+ /* read back in case value is clamped */
+ ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
+ sc->sc_curtxpow = txpow;
+ }
+}
+
+/* Return the current country and domain information */
+void ath_get_currentCountry(struct ath_softc *sc,
+ struct ath9k_country_entry *ctry)
+{
+ ath9k_regd_get_current_country(sc->sc_ah, ctry);
+
+ /* If HAL not specific yet, since it is band dependent,
+ * use the one we passed in. */
+ if (ctry->countryCode == CTRY_DEFAULT) {
+ ctry->iso[0] = 0;
+ ctry->iso[1] = 0;
+ } else if (ctry->iso[0] && ctry->iso[1]) {
+ if (!ctry->iso[2]) {
+ if (ath_outdoor)
+ ctry->iso[2] = 'O';
+ else
+ ctry->iso[2] = 'I';
+ }
+ }
+}
+
+/**************************/
+/* Slow Antenna Diversity */
+/**************************/
+
+void ath_slow_ant_div_init(struct ath_antdiv *antdiv,
+ struct ath_softc *sc,
+ int32_t rssitrig)
+{
+ int trig;
+
+ /* antdivf_rssitrig can range from 40 - 0xff */
+ trig = (rssitrig > 0xff) ? 0xff : rssitrig;
+ trig = (rssitrig < 40) ? 40 : rssitrig;
+
+ antdiv->antdiv_sc = sc;
+ antdiv->antdivf_rssitrig = trig;
+}
+
+void ath_slow_ant_div_start(struct ath_antdiv *antdiv,
+ u8 num_antcfg,
+ const u8 *bssid)
+{
+ antdiv->antdiv_num_antcfg =
+ num_antcfg < ATH_ANT_DIV_MAX_CFG ?
+ num_antcfg : ATH_ANT_DIV_MAX_CFG;
+ antdiv->antdiv_state = ATH_ANT_DIV_IDLE;
+ antdiv->antdiv_curcfg = 0;
+ antdiv->antdiv_bestcfg = 0;
+ antdiv->antdiv_laststatetsf = 0;
+
+ memcpy(antdiv->antdiv_bssid, bssid, sizeof(antdiv->antdiv_bssid));
+
+ antdiv->antdiv_start = 1;
+}
+
+void ath_slow_ant_div_stop(struct ath_antdiv *antdiv)
+{
+ antdiv->antdiv_start = 0;
+}
+
+static int32_t ath_find_max_val(int32_t *val,
+ u8 num_val, u8 *max_index)
+{
+ u32 MaxVal = *val++;
+ u32 cur_index = 0;
+
+ *max_index = 0;
+ while (++cur_index < num_val) {
+ if (*val > MaxVal) {
+ MaxVal = *val;
+ *max_index = cur_index;
+ }
+
+ val++;
+ }
+
+ return MaxVal;
+}
+
+void ath_slow_ant_div(struct ath_antdiv *antdiv,
+ struct ieee80211_hdr *hdr,
+ struct ath_rx_status *rx_stats)
+{
+ struct ath_softc *sc = antdiv->antdiv_sc;
+ struct ath_hal *ah = sc->sc_ah;
+ u64 curtsf = 0;
+ u8 bestcfg, curcfg = antdiv->antdiv_curcfg;
+ __le16 fc = hdr->frame_control;
+
+ if (antdiv->antdiv_start && ieee80211_is_beacon(fc)
+ && !compare_ether_addr(hdr->addr3, antdiv->antdiv_bssid)) {
+ antdiv->antdiv_lastbrssi[curcfg] = rx_stats->rs_rssi;
+ antdiv->antdiv_lastbtsf[curcfg] = ath9k_hw_gettsf64(sc->sc_ah);
+ curtsf = antdiv->antdiv_lastbtsf[curcfg];
+ } else {
+ return;
+ }
+
+ switch (antdiv->antdiv_state) {
+ case ATH_ANT_DIV_IDLE:
+ if ((antdiv->antdiv_lastbrssi[curcfg] <
+ antdiv->antdivf_rssitrig)
+ && ((curtsf - antdiv->antdiv_laststatetsf) >
+ ATH_ANT_DIV_MIN_IDLE_US)) {
+
+ curcfg++;
+ if (curcfg == antdiv->antdiv_num_antcfg)
+ curcfg = 0;
+
+ if (!ath9k_hw_select_antconfig(ah, curcfg)) {
+ antdiv->antdiv_bestcfg = antdiv->antdiv_curcfg;
+ antdiv->antdiv_curcfg = curcfg;
+ antdiv->antdiv_laststatetsf = curtsf;
+ antdiv->antdiv_state = ATH_ANT_DIV_SCAN;
+ }
+ }
+ break;
+
+ case ATH_ANT_DIV_SCAN:
+ if ((curtsf - antdiv->antdiv_laststatetsf) <
+ ATH_ANT_DIV_MIN_SCAN_US)
+ break;
+
+ curcfg++;
+ if (curcfg == antdiv->antdiv_num_antcfg)
+ curcfg = 0;
+
+ if (curcfg == antdiv->antdiv_bestcfg) {
+ ath_find_max_val(antdiv->antdiv_lastbrssi,
+ antdiv->antdiv_num_antcfg, &bestcfg);
+ if (!ath9k_hw_select_antconfig(ah, bestcfg)) {
+ antdiv->antdiv_bestcfg = bestcfg;
+ antdiv->antdiv_curcfg = bestcfg;
+ antdiv->antdiv_laststatetsf = curtsf;
+ antdiv->antdiv_state = ATH_ANT_DIV_IDLE;
+ }
+ } else {
+ if (!ath9k_hw_select_antconfig(ah, curcfg)) {
+ antdiv->antdiv_curcfg = curcfg;
+ antdiv->antdiv_laststatetsf = curtsf;
+ antdiv->antdiv_state = ATH_ANT_DIV_SCAN;
+ }
+ }
+
+ break;
+ }
+}
+
+/***********************/
+/* Descriptor Handling */
+/***********************/
+
+/*
+ * Set up DMA descriptors
+ *
+ * This function will allocate both the DMA descriptor structure, and the
+ * buffers it contains. These are used to contain the descriptors used
+ * by the system.
+*/
+
+int ath_descdma_setup(struct ath_softc *sc,
+ struct ath_descdma *dd,
+ struct list_head *head,
+ const char *name,
+ int nbuf,
+ int ndesc)
+{
+#define DS2PHYS(_dd, _ds) \
+ ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc))
+#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0)
+#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096)
+
+ struct ath_desc *ds;
+ struct ath_buf *bf;
+ int i, bsize, error;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA: %u buffers %u desc/buf\n",
+ __func__, name, nbuf, ndesc);
+
+ /* ath_desc must be a multiple of DWORDs */
+ if ((sizeof(struct ath_desc) % 4) != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: ath_desc not DWORD aligned\n",
+ __func__);
+ ASSERT((sizeof(struct ath_desc) % 4) == 0);
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ dd->dd_name = name;
+ dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
+
+ /*
+ * Need additional DMA memory because we can't use
+ * descriptors that cross the 4K page boundary. Assume
+ * one skipped descriptor per 4K page.
+ */
+ if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+ u32 ndesc_skipped =
+ ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len);
+ u32 dma_len;
+
+ while (ndesc_skipped) {
+ dma_len = ndesc_skipped * sizeof(struct ath_desc);
+ dd->dd_desc_len += dma_len;
+
+ ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
+ };
+ }
+
+ /* allocate descriptors */
+ dd->dd_desc = pci_alloc_consistent(sc->pdev,
+ dd->dd_desc_len,
+ &dd->dd_desc_paddr);
+ if (dd->dd_desc == NULL) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ ds = dd->dd_desc;
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA map: %p (%u) -> %llx (%u)\n",
+ __func__, dd->dd_name, ds, (u32) dd->dd_desc_len,
+ ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
+
+ /* allocate buffers */
+ bsize = sizeof(struct ath_buf) * nbuf;
+ bf = kmalloc(bsize, GFP_KERNEL);
+ if (bf == NULL) {
+ error = -ENOMEM;
+ goto fail2;
+ }
+ memzero(bf, bsize);
+ dd->dd_bufptr = bf;
+
+ INIT_LIST_HEAD(head);
+ for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
+ bf->bf_desc = ds;
+ bf->bf_daddr = DS2PHYS(dd, ds);
+
+ if (!(sc->sc_ah->ah_caps.hw_caps &
+ ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+ /*
+ * Skip descriptor addresses which can cause 4KB
+ * boundary crossing (addr + length) with a 32 dword
+ * descriptor fetch.
+ */
+ while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
+ ASSERT((caddr_t) bf->bf_desc <
+ ((caddr_t) dd->dd_desc +
+ dd->dd_desc_len));
+
+ ds += ndesc;
+ bf->bf_desc = ds;
+ bf->bf_daddr = DS2PHYS(dd, ds);
+ }
+ }
+ list_add_tail(&bf->list, head);
+ }
+ return 0;
+fail2:
+ pci_free_consistent(sc->pdev,
+ dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
+fail:
+ memzero(dd, sizeof(*dd));
+ return error;
+#undef ATH_DESC_4KB_BOUND_CHECK
+#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED
+#undef DS2PHYS
+}
+
+/*
+ * Cleanup DMA descriptors
+ *
+ * This function will free the DMA block that was allocated for the descriptor
+ * pool. Since this was allocated as one "chunk", it is freed in the same
+ * manner.
+*/
+
+void ath_descdma_cleanup(struct ath_softc *sc,
+ struct ath_descdma *dd,
+ struct list_head *head)
+{
+ /* Free memory associated with descriptors */
+ pci_free_consistent(sc->pdev,
+ dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
+
+ INIT_LIST_HEAD(head);
+ kfree(dd->dd_bufptr);
+ memzero(dd, sizeof(*dd));
+}
+
+/*************/
+/* Utilities */
+/*************/
+
+void ath_internal_reset(struct ath_softc *sc)
+{
+ ath_reset_start(sc, 0);
+ ath_reset(sc);
+ ath_reset_end(sc, 0);
+}
+
+int ath_get_hal_qnum(u16 queue, struct ath_softc *sc)
+{
+ int qnum;
+
+ switch (queue) {
+ case 0:
+ qnum = sc->sc_haltype2q[ATH9K_WME_AC_VO];
+ break;
+ case 1:
+ qnum = sc->sc_haltype2q[ATH9K_WME_AC_VI];
+ break;
+ case 2:
+ qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
+ break;
+ case 3:
+ qnum = sc->sc_haltype2q[ATH9K_WME_AC_BK];
+ break;
+ default:
+ qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE];
+ break;
+ }
+
+ return qnum;
+}
+
+int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
+{
+ int qnum;
+
+ switch (queue) {
+ case ATH9K_WME_AC_VO:
+ qnum = 0;
+ break;
+ case ATH9K_WME_AC_VI:
+ qnum = 1;
+ break;
+ case ATH9K_WME_AC_BE:
+ qnum = 2;
+ break;
+ case ATH9K_WME_AC_BK:
+ qnum = 3;
+ break;
+ default:
+ qnum = -1;
+ break;
+ }
+
+ return qnum;
+}
+
+
+/*
+ * Expand time stamp to TSF
+ *
+ * Extend 15-bit time stamp from rx descriptor to
+ * a full 64-bit TSF using the current h/w TSF.
+*/
+
+u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
+{
+ u64 tsf;
+
+ tsf = ath9k_hw_gettsf64(sc->sc_ah);
+ if ((tsf & 0x7fff) < rstamp)
+ tsf -= 0x8000;
+ return (tsf & ~0x7fff) | rstamp;
+}
+
+/*
+ * Set Default Antenna
+ *
+ * Call into the HAL to set the default antenna to use. Not really valid for
+ * MIMO technology.
+*/
+
+void ath_setdefantenna(void *context, u32 antenna)
+{
+ struct ath_softc *sc = (struct ath_softc *)context;
+ struct ath_hal *ah = sc->sc_ah;
+
+ /* XXX block beacon interrupts */
+ ath9k_hw_setantenna(ah, antenna);
+ sc->sc_defant = antenna;
+ sc->sc_rxotherant = 0;
+}
+
+/*
+ * Set Slot Time
+ *
+ * This will wake up the chip if required, and set the slot time for the
+ * frame (maximum transmit time). Slot time is assumed to be already set
+ * in the ATH object member sc_slottime
+*/
+
+void ath_setslottime(struct ath_softc *sc)
+{
+ ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime);
+ sc->sc_updateslot = OK;
+}
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
new file mode 100644
index 00000000000..4ee695b76b8
--- /dev/null
+++ b/drivers/net/wireless/ath9k/core.h
@@ -0,0 +1,1073 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef CORE_H
+#define CORE_H
+
+#include <linux/version.h>
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <asm/byteorder.h>
+#include <linux/scatterlist.h>
+#include <asm/page.h>
+#include <net/mac80211.h>
+
+#include "ath9k.h"
+#include "rc.h"
+
+struct ath_node;
+
+/******************/
+/* Utility macros */
+/******************/
+
+/* Macro to expand scalars to 64-bit objects */
+
+#define ito64(x) (sizeof(x) == 8) ? \
+ (((unsigned long long int)(x)) & (0xff)) : \
+ (sizeof(x) == 16) ? \
+ (((unsigned long long int)(x)) & 0xffff) : \
+ ((sizeof(x) == 32) ? \
+ (((unsigned long long int)(x)) & 0xffffffff) : \
+ (unsigned long long int)(x))
+
+/* increment with wrap-around */
+#define INCR(_l, _sz) do { \
+ (_l)++; \
+ (_l) &= ((_sz) - 1); \
+ } while (0)
+
+/* decrement with wrap-around */
+#define DECR(_l, _sz) do { \
+ (_l)--; \
+ (_l) &= ((_sz) - 1); \
+ } while (0)
+
+#define A_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define ASSERT(exp) do { \
+ if (unlikely(!(exp))) { \
+ BUG(); \
+ } \
+ } while (0)
+
+/* XXX: remove */
+#define memzero(_buf, _len) memset(_buf, 0, _len)
+
+#define get_dma_mem_context(var, field) (&((var)->field))
+#define copy_dma_mem_context(dst, src) (*dst = *src)
+
+#define ATH9K_BH_STATUS_INTACT 0
+#define ATH9K_BH_STATUS_CHANGE 1
+
+#define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<<i))
+
+static inline unsigned long get_timestamp(void)
+{
+ return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ);
+}
+
+/*************/
+/* Debugging */
+/*************/
+
+enum ATH_DEBUG {
+ ATH_DBG_RESET = 0x00000001,
+ ATH_DBG_PHY_IO = 0x00000002,
+ ATH_DBG_REG_IO = 0x00000004,
+ ATH_DBG_QUEUE = 0x00000008,
+ ATH_DBG_EEPROM = 0x00000010,
+ ATH_DBG_NF_CAL = 0x00000020,
+ ATH_DBG_CALIBRATE = 0x00000040,
+ ATH_DBG_CHANNEL = 0x00000080,
+ ATH_DBG_INTERRUPT = 0x00000100,
+ ATH_DBG_REGULATORY = 0x00000200,
+ ATH_DBG_ANI = 0x00000400,
+ ATH_DBG_POWER_MGMT = 0x00000800,
+ ATH_DBG_XMIT = 0x00001000,
+ ATH_DBG_BEACON = 0x00002000,
+ ATH_DBG_RATE = 0x00004000,
+ ATH_DBG_CONFIG = 0x00008000,
+ ATH_DBG_KEYCACHE = 0x00010000,
+ ATH_DBG_AGGR = 0x00020000,
+ ATH_DBG_FATAL = 0x00040000,
+ ATH_DBG_ANY = 0xffffffff
+};
+
+#define DBG_DEFAULT (ATH_DBG_FATAL)
+
+#define DPRINTF(sc, _m, _fmt, ...) do { \
+ if (sc->sc_debug & (_m)) \
+ printk(_fmt , ##__VA_ARGS__); \
+ } while (0)
+
+/***************************/
+/* Load-time Configuration */
+/***************************/
+
+/* Per-instance load-time (note: NOT run-time) configurations
+ * for Atheros Device */
+struct ath_config {
+ u32 ath_aggr_prot;
+ u16 txpowlimit;
+ u16 txpowlimit_override;
+ u8 cabqReadytime; /* Cabq Readytime % */
+ u8 swBeaconProcess; /* Process received beacons in SW (vs HW) */
+};
+
+/***********************/
+/* Chainmask Selection */
+/***********************/
+
+#define ATH_CHAINMASK_SEL_TIMEOUT 6000
+/* Default - Number of last RSSI values that is used for
+ * chainmask selection */
+#define ATH_CHAINMASK_SEL_RSSI_CNT 10
+/* Means use 3x3 chainmask instead of configured chainmask */
+#define ATH_CHAINMASK_SEL_3X3 7
+/* Default - Rssi threshold below which we have to switch to 3x3 */
+#define ATH_CHAINMASK_SEL_UP_RSSI_THRES 20
+/* Default - Rssi threshold above which we have to switch to
+ * user configured values */
+#define ATH_CHAINMASK_SEL_DOWN_RSSI_THRES 35
+/* Struct to store the chainmask select related info */
+struct ath_chainmask_sel {
+ struct timer_list timer;
+ int cur_tx_mask; /* user configured or 3x3 */
+ int cur_rx_mask; /* user configured or 3x3 */
+ int tx_avgrssi;
+ u8 switch_allowed:1, /* timer will set this */
+ cm_sel_enabled : 1;
+};
+
+int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an);
+void ath_update_chainmask(struct ath_softc *sc, int is_ht);
+
+/*************************/
+/* Descriptor Management */
+/*************************/
+
+/* Number of descriptors per buffer. The only case where we see skbuff
+chains is due to FF aggregation in the driver. */
+#define ATH_TXDESC 1
+/* if there's more fragment for this MSDU */
+#define ATH_BF_MORE_MPDU 1
+#define ATH_TXBUF_RESET(_bf) do { \
+ (_bf)->bf_status = 0; \
+ (_bf)->bf_lastbf = NULL; \
+ (_bf)->bf_lastfrm = NULL; \
+ (_bf)->bf_next = NULL; \
+ memzero(&((_bf)->bf_state), \
+ sizeof(struct ath_buf_state)); \
+ } while (0)
+
+struct ath_buf_state {
+ int bfs_nframes; /* # frames in aggregate */
+ u16 bfs_al; /* length of aggregate */
+ u16 bfs_frmlen; /* length of frame */
+ int bfs_seqno; /* sequence number */
+ int bfs_tidno; /* tid of this frame */
+ int bfs_retries; /* current retries */
+ struct ath_rc_series bfs_rcs[4]; /* rate series */
+ u8 bfs_isdata:1; /* is a data frame/aggregate */
+ u8 bfs_isaggr:1; /* is an aggregate */
+ u8 bfs_isampdu:1; /* is an a-mpdu, aggregate or not */
+ u8 bfs_ht:1; /* is an HT frame */
+ u8 bfs_isretried:1; /* is retried */
+ u8 bfs_isxretried:1; /* is excessive retried */
+ u8 bfs_shpreamble:1; /* is short preamble */
+ u8 bfs_isbar:1; /* is a BAR */
+ u8 bfs_ispspoll:1; /* is a PS-Poll */
+ u8 bfs_aggrburst:1; /* is a aggr burst */
+ u8 bfs_calcairtime:1; /* requests airtime be calculated
+ when set for tx frame */
+ int bfs_rifsburst_elem; /* RIFS burst/bar */
+ int bfs_nrifsubframes; /* # of elements in burst */
+ /* key type use to encrypt this frame */
+ enum ath9k_key_type bfs_keytype;
+};
+
+#define bf_nframes bf_state.bfs_nframes
+#define bf_al bf_state.bfs_al
+#define bf_frmlen bf_state.bfs_frmlen
+#define bf_retries bf_state.bfs_retries
+#define bf_seqno bf_state.bfs_seqno
+#define bf_tidno bf_state.bfs_tidno
+#define bf_rcs bf_state.bfs_rcs
+#define bf_isdata bf_state.bfs_isdata
+#define bf_isaggr bf_state.bfs_isaggr
+#define bf_isampdu bf_state.bfs_isampdu
+#define bf_ht bf_state.bfs_ht
+#define bf_isretried bf_state.bfs_isretried
+#define bf_isxretried bf_state.bfs_isxretried
+#define bf_shpreamble bf_state.bfs_shpreamble
+#define bf_rifsburst_elem bf_state.bfs_rifsburst_elem
+#define bf_nrifsubframes bf_state.bfs_nrifsubframes
+#define bf_keytype bf_state.bfs_keytype
+#define bf_isbar bf_state.bfs_isbar
+#define bf_ispspoll bf_state.bfs_ispspoll
+#define bf_aggrburst bf_state.bfs_aggrburst
+#define bf_calcairtime bf_state.bfs_calcairtime
+
+/*
+ * Abstraction of a contiguous buffer to transmit/receive. There is only
+ * a single hw descriptor encapsulated here.
+ */
+
+struct ath_buf {
+ struct list_head list;
+ struct list_head *last;
+ struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
+ an aggregate) */
+ struct ath_buf *bf_lastfrm; /* last buf of this frame */
+ struct ath_buf *bf_next; /* next subframe in the aggregate */
+ struct ath_buf *bf_rifslast; /* last buf for RIFS burst */
+ void *bf_mpdu; /* enclosing frame structure */
+ void *bf_node; /* pointer to the node */
+ struct ath_desc *bf_desc; /* virtual addr of desc */
+ dma_addr_t bf_daddr; /* physical addr of desc */
+ dma_addr_t bf_buf_addr; /* physical addr of data buffer */
+ u32 bf_status;
+ u16 bf_flags; /* tx descriptor flags */
+ struct ath_buf_state bf_state; /* buffer state */
+ dma_addr_t bf_dmacontext;
+};
+
+/*
+ * reset the rx buffer.
+ * any new fields added to the athbuf and require
+ * reset need to be added to this macro.
+ * currently bf_status is the only one requires that
+ * requires reset.
+ */
+#define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0)
+
+/* hw processing complete, desc processed by hal */
+#define ATH_BUFSTATUS_DONE 0x00000001
+/* hw processing complete, desc hold for hw */
+#define ATH_BUFSTATUS_STALE 0x00000002
+/* Rx-only: OS is done with this packet and it's ok to queued it to hw */
+#define ATH_BUFSTATUS_FREE 0x00000004
+
+/* DMA state for tx/rx descriptors */
+
+struct ath_descdma {
+ const char *dd_name;
+ struct ath_desc *dd_desc; /* descriptors */
+ dma_addr_t dd_desc_paddr; /* physical addr of dd_desc */
+ u32 dd_desc_len; /* size of dd_desc */
+ struct ath_buf *dd_bufptr; /* associated buffers */
+ dma_addr_t dd_dmacontext;
+};
+
+/* Abstraction of a received RX MPDU/MMPDU, or a RX fragment */
+
+struct ath_rx_context {
+ struct ath_buf *ctx_rxbuf; /* associated ath_buf for rx */
+};
+#define ATH_RX_CONTEXT(skb) ((struct ath_rx_context *)skb->cb)
+
+int ath_descdma_setup(struct ath_softc *sc,
+ struct ath_descdma *dd,
+ struct list_head *head,
+ const char *name,
+ int nbuf,
+ int ndesc);
+int ath_desc_alloc(struct ath_softc *sc);
+void ath_desc_free(struct ath_softc *sc);
+void ath_descdma_cleanup(struct ath_softc *sc,
+ struct ath_descdma *dd,
+ struct list_head *head);
+
+/******/
+/* RX */
+/******/
+
+#define ATH_MAX_ANTENNA 3
+#define ATH_RXBUF 512
+#define ATH_RX_TIMEOUT 40 /* 40 milliseconds */
+#define WME_NUM_TID 16
+#define IEEE80211_BAR_CTL_TID_M 0xF000 /* tid mask */
+#define IEEE80211_BAR_CTL_TID_S 2 /* tid shift */
+
+enum ATH_RX_TYPE {
+ ATH_RX_NON_CONSUMED = 0,
+ ATH_RX_CONSUMED
+};
+
+/* per frame rx status block */
+struct ath_recv_status {
+ u64 tsf; /* mac tsf */
+ int8_t rssi; /* RSSI (noise floor ajusted) */
+ int8_t rssictl[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */
+ int8_t rssiextn[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */
+ int8_t abs_rssi; /* absolute RSSI */
+ u8 rateieee; /* data rate received (IEEE rate code) */
+ u8 ratecode; /* phy rate code */
+ int rateKbps; /* data rate received (Kbps) */
+ int antenna; /* rx antenna */
+ int flags; /* status of associated skb */
+#define ATH_RX_FCS_ERROR 0x01
+#define ATH_RX_MIC_ERROR 0x02
+#define ATH_RX_DECRYPT_ERROR 0x04
+#define ATH_RX_RSSI_VALID 0x08
+/* if any of ctl,extn chainrssis are valid */
+#define ATH_RX_CHAIN_RSSI_VALID 0x10
+/* if extn chain rssis are valid */
+#define ATH_RX_RSSI_EXTN_VALID 0x20
+/* set if 40Mhz, clear if 20Mhz */
+#define ATH_RX_40MHZ 0x40
+/* set if short GI, clear if full GI */
+#define ATH_RX_SHORT_GI 0x80
+};
+
+struct ath_rxbuf {
+ struct sk_buff *rx_wbuf;
+ unsigned long rx_time; /* system time when received */
+ struct ath_recv_status rx_status; /* cached rx status */
+};
+
+/* Per-TID aggregate receiver state for a node */
+struct ath_arx_tid {
+ struct ath_node *an;
+ struct ath_rxbuf *rxbuf; /* re-ordering buffer */
+ struct timer_list timer;
+ spinlock_t tidlock;
+ int baw_head; /* seq_next at head */
+ int baw_tail; /* tail of block-ack window */
+ int seq_reset; /* need to reset start sequence */
+ int addba_exchangecomplete;
+ u16 seq_next; /* next expected sequence */
+ u16 baw_size; /* block-ack window size */
+};
+
+/* Per-node receiver aggregate state */
+struct ath_arx {
+ struct ath_arx_tid tid[WME_NUM_TID];
+};
+
+int ath_startrecv(struct ath_softc *sc);
+bool ath_stoprecv(struct ath_softc *sc);
+void ath_flushrecv(struct ath_softc *sc);
+u32 ath_calcrxfilter(struct ath_softc *sc);
+void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an);
+void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an);
+void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
+void ath_handle_rx_intr(struct ath_softc *sc);
+int ath_rx_init(struct ath_softc *sc, int nbufs);
+void ath_rx_cleanup(struct ath_softc *sc);
+int ath_rx_tasklet(struct ath_softc *sc, int flush);
+int ath_rx_input(struct ath_softc *sc,
+ struct ath_node *node,
+ int is_ampdu,
+ struct sk_buff *skb,
+ struct ath_recv_status *rx_status,
+ enum ATH_RX_TYPE *status);
+int ath__rx_indicate(struct ath_softc *sc,
+ struct sk_buff *skb,
+ struct ath_recv_status *status,
+ u16 keyix);
+int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb,
+ struct ath_recv_status *status);
+
+/******/
+/* TX */
+/******/
+
+#define ATH_FRAG_PER_MSDU 1
+#define ATH_TXBUF (512/ATH_FRAG_PER_MSDU)
+/* max number of transmit attempts (tries) */
+#define ATH_TXMAXTRY 13
+/* max number of 11n transmit attempts (tries) */
+#define ATH_11N_TXMAXTRY 10
+/* max number of tries for management and control frames */
+#define ATH_MGT_TXMAXTRY 4
+#define WME_BA_BMP_SIZE 64
+#define WME_MAX_BA WME_BA_BMP_SIZE
+#define ATH_TID_MAX_BUFS (2 * WME_MAX_BA)
+#define TID_TO_WME_AC(_tid) \
+ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
+ (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
+ (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
+ WME_AC_VO)
+
+
+/* Wireless Multimedia Extension Defines */
+#define WME_AC_BE 0 /* best effort */
+#define WME_AC_BK 1 /* background */
+#define WME_AC_VI 2 /* video */
+#define WME_AC_VO 3 /* voice */
+#define WME_NUM_AC 4
+
+enum ATH_SM_PWRSAV{
+ ATH_SM_ENABLE,
+ ATH_SM_PWRSAV_STATIC,
+ ATH_SM_PWRSAV_DYNAMIC,
+};
+
+/*
+ * Data transmit queue state. One of these exists for each
+ * hardware transmit queue. Packets sent to us from above
+ * are assigned to queues based on their priority. Not all
+ * devices support a complete set of hardware transmit queues.
+ * For those devices the array sc_ac2q will map multiple
+ * priorities to fewer hardware queues (typically all to one
+ * hardware queue).
+ */
+struct ath_txq {
+ u32 axq_qnum; /* hardware q number */
+ u32 *axq_link; /* link ptr in last TX desc */
+ struct list_head axq_q; /* transmit queue */
+ spinlock_t axq_lock;
+ unsigned long axq_lockflags; /* intr state when must cli */
+ u32 axq_depth; /* queue depth */
+ u8 axq_aggr_depth; /* aggregates queued */
+ u32 axq_totalqueued; /* total ever queued */
+
+ /* count to determine if descriptor should generate int on this txq. */
+ u32 axq_intrcnt;
+
+ bool stopped; /* Is mac80211 queue stopped ? */
+ struct ath_buf *axq_linkbuf; /* virtual addr of last buffer*/
+
+ /* first desc of the last descriptor that contains CTS */
+ struct ath_desc *axq_lastdsWithCTS;
+
+ /* final desc of the gating desc that determines whether
+ lastdsWithCTS has been DMA'ed or not */
+ struct ath_desc *axq_gatingds;
+
+ struct list_head axq_acq;
+};
+
+/* per TID aggregate tx state for a destination */
+struct ath_atx_tid {
+ struct list_head list; /* round-robin tid entry */
+ struct list_head buf_q; /* pending buffers */
+ struct ath_node *an;
+ struct ath_atx_ac *ac;
+ struct ath_buf *tx_buf[ATH_TID_MAX_BUFS]; /* active tx frames */
+ u16 seq_start;
+ u16 seq_next;
+ u16 baw_size;
+ int tidno;
+ int baw_head; /* first un-acked tx buffer */
+ int baw_tail; /* next unused tx buffer slot */
+ int sched;
+ int paused;
+ int cleanup_inprogress;
+ u32 addba_exchangecomplete:1;
+ int32_t addba_exchangeinprogress;
+ int addba_exchangeattempts;
+};
+
+/* per access-category aggregate tx state for a destination */
+struct ath_atx_ac {
+ int sched; /* dest-ac is scheduled */
+ int qnum; /* H/W queue number associated
+ with this AC */
+ struct list_head list; /* round-robin txq entry */
+ struct list_head tid_q; /* queue of TIDs with buffers */
+};
+
+/* per dest tx state */
+struct ath_atx {
+ struct ath_atx_tid tid[WME_NUM_TID];
+ struct ath_atx_ac ac[WME_NUM_AC];
+};
+
+/* per-frame tx control block */
+struct ath_tx_control {
+ struct ath_node *an;
+ int if_id;
+ int qnum;
+ u32 ht:1;
+ u32 ps:1;
+ u32 use_minrate:1;
+ enum ath9k_pkt_type atype;
+ enum ath9k_key_type keytype;
+ u32 flags;
+ u16 seqno;
+ u16 tidno;
+ u16 txpower;
+ u16 frmlen;
+ u32 keyix;
+ int min_rate;
+ int mcast_rate;
+ u16 nextfraglen;
+ struct ath_softc *dev;
+ dma_addr_t dmacontext;
+};
+
+/* per frame tx status block */
+struct ath_xmit_status {
+ int retries; /* number of retries to successufully
+ transmit this frame */
+ int flags; /* status of transmit */
+#define ATH_TX_ERROR 0x01
+#define ATH_TX_XRETRY 0x02
+#define ATH_TX_BAR 0x04
+};
+
+struct ath_tx_stat {
+ int rssi; /* RSSI (noise floor ajusted) */
+ int rssictl[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */
+ int rssiextn[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */
+ int rateieee; /* data rate xmitted (IEEE rate code) */
+ int rateKbps; /* data rate xmitted (Kbps) */
+ int ratecode; /* phy rate code */
+ int flags; /* validity flags */
+/* if any of ctl,extn chain rssis are valid */
+#define ATH_TX_CHAIN_RSSI_VALID 0x01
+/* if extn chain rssis are valid */
+#define ATH_TX_RSSI_EXTN_VALID 0x02
+ u32 airtime; /* time on air per final tx rate */
+};
+
+struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
+void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
+int ath_tx_setup(struct ath_softc *sc, int haltype);
+void ath_draintxq(struct ath_softc *sc, bool retry_tx);
+void ath_tx_draintxq(struct ath_softc *sc,
+ struct ath_txq *txq, bool retry_tx);
+void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an);
+void ath_tx_node_cleanup(struct ath_softc *sc,
+ struct ath_node *an, bool bh_flag);
+void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an);
+void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
+int ath_tx_init(struct ath_softc *sc, int nbufs);
+int ath_tx_cleanup(struct ath_softc *sc);
+int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
+int ath_txq_update(struct ath_softc *sc, int qnum,
+ struct ath9k_tx_queue_info *q);
+int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb);
+void ath_tx_tasklet(struct ath_softc *sc);
+u32 ath_txq_depth(struct ath_softc *sc, int qnum);
+u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum);
+void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth);
+void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
+ struct ath_xmit_status *tx_status, struct ath_node *an);
+
+/**********************/
+/* Node / Aggregation */
+/**********************/
+
+/* indicates the node is clened up */
+#define ATH_NODE_CLEAN 0x1
+/* indicates the node is 80211 power save */
+#define ATH_NODE_PWRSAVE 0x2
+
+#define ADDBA_TIMEOUT 200 /* 200 milliseconds */
+#define ADDBA_EXCHANGE_ATTEMPTS 10
+#define ATH_AGGR_DELIM_SZ 4 /* delimiter size */
+#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */
+/* number of delimiters for encryption padding */
+#define ATH_AGGR_ENCRYPTDELIM 10
+/* minimum h/w qdepth to be sustained to maximize aggregation */
+#define ATH_AGGR_MIN_QDEPTH 2
+#define ATH_AMPDU_SUBFRAME_DEFAULT 32
+#define IEEE80211_SEQ_SEQ_SHIFT 4
+#define IEEE80211_SEQ_MAX 4096
+#define IEEE80211_MIN_AMPDU_BUF 0x8
+
+/* return whether a bit at index _n in bitmap _bm is set
+ * _sz is the size of the bitmap */
+#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \
+ ((_bm)[(_n) >> 5] & (1 << ((_n) & 31))))
+
+/* return block-ack bitmap index given sequence and starting sequence */
+#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1))
+
+/* returns delimiter padding required given the packet length */
+#define ATH_AGGR_GET_NDELIM(_len) \
+ (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \
+ (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2)
+
+#define BAW_WITHIN(_start, _bawsz, _seqno) \
+ ((((_seqno) - (_start)) & 4095) < (_bawsz))
+
+#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum)
+#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low)
+#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
+#define ATH_AN_2_TID(_an, _tidno) (&(_an)->an_aggr.tx.tid[(_tidno)])
+
+enum ATH_AGGR_STATUS {
+ ATH_AGGR_DONE,
+ ATH_AGGR_BAW_CLOSED,
+ ATH_AGGR_LIMITED,
+ ATH_AGGR_SHORTPKT,
+ ATH_AGGR_8K_LIMITED,
+};
+
+enum ATH_AGGR_CHECK {
+ AGGR_NOT_REQUIRED,
+ AGGR_REQUIRED,
+ AGGR_CLEANUP_PROGRESS,
+ AGGR_EXCHANGE_PROGRESS,
+ AGGR_EXCHANGE_DONE
+};
+
+struct aggr_rifs_param {
+ int param_max_frames;
+ int param_max_len;
+ int param_rl;
+ int param_al;
+ struct ath_rc_series *param_rcs;
+};
+
+/* Per-node aggregation state */
+struct ath_node_aggr {
+ struct ath_atx tx; /* node transmit state */
+ struct ath_arx rx; /* node receive state */
+};
+
+/* driver-specific node state */
+struct ath_node {
+ struct list_head list;
+ struct ath_softc *an_sc;
+ atomic_t an_refcnt;
+ struct ath_chainmask_sel an_chainmask_sel;
+ struct ath_node_aggr an_aggr;
+ u8 an_smmode; /* SM Power save mode */
+ u8 an_flags;
+ u8 an_addr[ETH_ALEN];
+};
+
+void ath_tx_resume_tid(struct ath_softc *sc,
+ struct ath_atx_tid *tid);
+enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc,
+ struct ath_node *an, u8 tidno);
+void ath_tx_aggr_teardown(struct ath_softc *sc,
+ struct ath_node *an, u8 tidno);
+void ath_rx_aggr_teardown(struct ath_softc *sc,
+ struct ath_node *an, u8 tidno);
+int ath_rx_aggr_start(struct ath_softc *sc,
+ const u8 *addr,
+ u16 tid,
+ u16 *ssn);
+int ath_rx_aggr_stop(struct ath_softc *sc,
+ const u8 *addr,
+ u16 tid);
+int ath_tx_aggr_start(struct ath_softc *sc,
+ const u8 *addr,
+ u16 tid,
+ u16 *ssn);
+int ath_tx_aggr_stop(struct ath_softc *sc,
+ const u8 *addr,
+ u16 tid);
+void ath_newassoc(struct ath_softc *sc,
+ struct ath_node *node, int isnew, int isuapsd);
+struct ath_node *ath_node_attach(struct ath_softc *sc,
+ u8 addr[ETH_ALEN], int if_id);
+void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag);
+struct ath_node *ath_node_get(struct ath_softc *sc, u8 addr[ETH_ALEN]);
+void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag);
+struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr);
+
+/*******************/
+/* Beacon Handling */
+/*******************/
+
+/*
+ * Regardless of the number of beacons we stagger, (i.e. regardless of the
+ * number of BSSIDs) if a given beacon does not go out even after waiting this
+ * number of beacon intervals, the game's up.
+ */
+#define BSTUCK_THRESH (9 * ATH_BCBUF)
+#define ATH_BCBUF 4 /* number of beacon buffers */
+#define ATH_DEFAULT_BINTVAL 100 /* default beacon interval in TU */
+#define ATH_DEFAULT_BMISS_LIMIT 10
+#define ATH_BEACON_AIFS_DEFAULT 0 /* Default aifs for ap beacon q */
+#define ATH_BEACON_CWMIN_DEFAULT 0 /* Default cwmin for ap beacon q */
+#define ATH_BEACON_CWMAX_DEFAULT 0 /* Default cwmax for ap beacon q */
+#define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024)
+
+/* beacon configuration */
+struct ath_beacon_config {
+ u16 beacon_interval;
+ u16 listen_interval;
+ u16 dtim_period;
+ u16 bmiss_timeout;
+ u8 dtim_count;
+ u8 tim_offset;
+ union {
+ u64 last_tsf;
+ u8 last_tstamp[8];
+ } u; /* last received beacon/probe response timestamp of this BSS. */
+};
+
+/* offsets in a beacon frame for
+ * quick acess of beacon content by low-level driver */
+struct ath_beacon_offset {
+ u8 *bo_tim; /* start of atim/dtim */
+};
+
+void ath9k_beacon_tasklet(unsigned long data);
+void ath_beacon_config(struct ath_softc *sc, int if_id);
+int ath_beaconq_setup(struct ath_hal *ah);
+int ath_beacon_alloc(struct ath_softc *sc, int if_id);
+void ath_bstuck_process(struct ath_softc *sc);
+void ath_beacon_tasklet(struct ath_softc *sc, int *needmark);
+void ath_beacon_free(struct ath_softc *sc);
+void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp);
+void ath_beacon_sync(struct ath_softc *sc, int if_id);
+void ath_update_beacon_info(struct ath_softc *sc, int avgbrssi);
+void ath_get_beaconconfig(struct ath_softc *sc,
+ int if_id,
+ struct ath_beacon_config *conf);
+int ath_update_beacon(struct ath_softc *sc,
+ int if_id,
+ struct ath_beacon_offset *bo,
+ struct sk_buff *skb,
+ int mcast);
+/********/
+/* VAPs */
+/********/
+
+/*
+ * Define the scheme that we select MAC address for multiple
+ * BSS on the same radio. The very first VAP will just use the MAC
+ * address from the EEPROM. For the next 3 VAPs, we set the
+ * U/L bit (bit 1) in MAC address, and use the next two bits as the
+ * index of the VAP.
+ */
+
+#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \
+ ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))
+
+/* VAP configuration (from protocol layer) */
+struct ath_vap_config {
+ u32 av_fixed_rateset;
+ u32 av_fixed_retryset;
+};
+
+/* driver-specific vap state */
+struct ath_vap {
+ struct ieee80211_vif *av_if_data;
+ enum ath9k_opmode av_opmode; /* VAP operational mode */
+ struct ath_buf *av_bcbuf; /* beacon buffer */
+ struct ath_beacon_offset av_boff; /* dynamic update state */
+ struct ath_tx_control av_btxctl; /* txctl information for beacon */
+ int av_bslot; /* beacon slot index */
+ struct ath_txq av_mcastq; /* multicast transmit queue */
+ struct ath_vap_config av_config;/* vap configuration parameters*/
+ struct ath_rate_node *rc_node;
+};
+
+int ath_vap_attach(struct ath_softc *sc,
+ int if_id,
+ struct ieee80211_vif *if_data,
+ enum ath9k_opmode opmode);
+int ath_vap_detach(struct ath_softc *sc, int if_id);
+int ath_vap_config(struct ath_softc *sc,
+ int if_id, struct ath_vap_config *if_config);
+int ath_vap_listen(struct ath_softc *sc, int if_id);
+
+/*********************/
+/* Antenna diversity */
+/*********************/
+
+#define ATH_ANT_DIV_MAX_CFG 2
+#define ATH_ANT_DIV_MIN_IDLE_US 1000000 /* us */
+#define ATH_ANT_DIV_MIN_SCAN_US 50000 /* us */
+
+enum ATH_ANT_DIV_STATE{
+ ATH_ANT_DIV_IDLE,
+ ATH_ANT_DIV_SCAN, /* evaluating antenna */
+};
+
+struct ath_antdiv {
+ struct ath_softc *antdiv_sc;
+ u8 antdiv_start;
+ enum ATH_ANT_DIV_STATE antdiv_state;
+ u8 antdiv_num_antcfg;
+ u8 antdiv_curcfg;
+ u8 antdiv_bestcfg;
+ int32_t antdivf_rssitrig;
+ int32_t antdiv_lastbrssi[ATH_ANT_DIV_MAX_CFG];
+ u64 antdiv_lastbtsf[ATH_ANT_DIV_MAX_CFG];
+ u64 antdiv_laststatetsf;
+ u8 antdiv_bssid[ETH_ALEN];
+};
+
+void ath_slow_ant_div_init(struct ath_antdiv *antdiv,
+ struct ath_softc *sc, int32_t rssitrig);
+void ath_slow_ant_div_start(struct ath_antdiv *antdiv,
+ u8 num_antcfg,
+ const u8 *bssid);
+void ath_slow_ant_div_stop(struct ath_antdiv *antdiv);
+void ath_slow_ant_div(struct ath_antdiv *antdiv,
+ struct ieee80211_hdr *wh,
+ struct ath_rx_status *rx_stats);
+void ath_setdefantenna(void *sc, u32 antenna);
+
+/********************/
+/* Main driver core */
+/********************/
+
+/*
+ * Default cache line size, in bytes.
+ * Used when PCI device not fully initialized by bootrom/BIOS
+*/
+#define DEFAULT_CACHELINE 32
+#define ATH_DEFAULT_NOISE_FLOOR -95
+#define ATH_REGCLASSIDS_MAX 10
+#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */
+#define ATH_PREAMBLE_SHORT (1<<0)
+#define ATH_PROTECT_ENABLE (1<<1)
+#define ATH_MAX_SW_RETRIES 10
+/* Num farmes difference in tx to flip default recv */
+#define ATH_ANTENNA_DIFF 2
+#define ATH_CHAN_MAX 255
+#define IEEE80211_WEP_NKID 4 /* number of key ids */
+#define IEEE80211_RATE_VAL 0x7f
+/*
+ * The key cache is used for h/w cipher state and also for
+ * tracking station state such as the current tx antenna.
+ * We also setup a mapping table between key cache slot indices
+ * and station state to short-circuit node lookups on rx.
+ * Different parts have different size key caches. We handle
+ * up to ATH_KEYMAX entries (could dynamically allocate state).
+ */
+#define ATH_KEYMAX 128 /* max key cache size we handle */
+
+#define RESET_RETRY_TXQ 0x00000001
+#define ATH_IF_ID_ANY 0xff
+
+#define ATH_TXPOWER_MAX 100 /* .5 dBm units */
+
+#define RSSI_LPF_THRESHOLD -20
+#define ATH_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */
+#define ATH_RATE_DUMMY_MARKER 0
+#define ATH_RSSI_LPF_LEN 10
+#define ATH_RSSI_DUMMY_MARKER 0x127
+
+#define ATH_EP_MUL(x, mul) ((x) * (mul))
+#define ATH_EP_RND(x, mul) \
+ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+#define ATH_RSSI_OUT(x) \
+ (((x) != ATH_RSSI_DUMMY_MARKER) ? \
+ (ATH_EP_RND((x), ATH_RSSI_EP_MULTIPLIER)) : ATH_RSSI_DUMMY_MARKER)
+#define ATH_RSSI_IN(x) \
+ (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
+#define ATH_LPF_RSSI(x, y, len) \
+ ((x != ATH_RSSI_DUMMY_MARKER) ? \
+ (((x) * ((len) - 1) + (y)) / (len)) : (y))
+#define ATH_RSSI_LPF(x, y) do { \
+ if ((y) >= RSSI_LPF_THRESHOLD) \
+ x = ATH_LPF_RSSI((x), \
+ ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
+ } while (0)
+
+
+enum PROT_MODE {
+ PROT_M_NONE = 0,
+ PROT_M_RTSCTS,
+ PROT_M_CTSONLY
+};
+
+enum RATE_TYPE {
+ NORMAL_RATE = 0,
+ HALF_RATE,
+ QUARTER_RATE
+};
+
+struct ath_ht_info {
+ enum ath9k_ht_macmode tx_chan_width;
+ u16 maxampdu;
+ u8 mpdudensity;
+ u8 ext_chan_offset;
+};
+
+struct ath_softc {
+ struct ieee80211_hw *hw;
+ struct pci_dev *pdev;
+ void __iomem *mem;
+ struct tasklet_struct intr_tq;
+ struct tasklet_struct bcon_tasklet;
+ struct ath_config sc_config; /* load-time parameters */
+ int sc_debug;
+ struct ath_hal *sc_ah;
+ struct ath_rate_softc *sc_rc; /* tx rate control support */
+ u32 sc_intrstatus;
+ enum ath9k_opmode sc_opmode; /* current operating mode */
+
+ u8 sc_invalid; /* being detached */
+ u8 sc_beacons; /* beacons running */
+ u8 sc_scanning; /* scanning active */
+ u8 sc_txaggr; /* enable 11n tx aggregation */
+ u8 sc_rxaggr; /* enable 11n rx aggregation */
+ u8 sc_update_chainmask; /* change chain mask */
+ u8 sc_full_reset; /* force full reset */
+ enum wireless_mode sc_curmode; /* current phy mode */
+ u16 sc_curtxpow;
+ u16 sc_curaid;
+ u8 sc_curbssid[ETH_ALEN];
+ u8 sc_myaddr[ETH_ALEN];
+ enum PROT_MODE sc_protmode;
+ u8 sc_mcastantenna;
+ u8 sc_txantenna; /* data tx antenna (fixed or auto) */
+ u8 sc_nbcnvaps; /* # of vaps sending beacons */
+ u16 sc_nvaps; /* # of active virtual ap's */
+ struct ath_vap *sc_vaps[ATH_BCBUF];
+ enum ath9k_int sc_imask;
+ u8 sc_bssidmask[ETH_ALEN];
+ u8 sc_defant; /* current default antenna */
+ u8 sc_rxotherant; /* rx's on non-default antenna */
+ u16 sc_cachelsz;
+ int sc_slotupdate; /* slot to next advance fsm */
+ int sc_slottime;
+ u8 sc_noreset;
+ int sc_bslot[ATH_BCBUF];
+ struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */
+ struct list_head node_list;
+ struct ath_ht_info sc_ht_info;
+ int16_t sc_noise_floor; /* signal noise floor in dBm */
+ enum ath9k_ht_extprotspacing sc_ht_extprotspacing;
+ u8 sc_tx_chainmask;
+ u8 sc_rx_chainmask;
+ u8 sc_rxchaindetect_ref;
+ u8 sc_rxchaindetect_thresh5GHz;
+ u8 sc_rxchaindetect_thresh2GHz;
+ u8 sc_rxchaindetect_delta5GHz;
+ u8 sc_rxchaindetect_delta2GHz;
+ u32 sc_rtsaggrlimit; /* Chipset specific aggr limit */
+ u32 sc_flags;
+#ifdef CONFIG_SLOW_ANT_DIV
+ struct ath_antdiv sc_antdiv;
+#endif
+ enum {
+ OK, /* no change needed */
+ UPDATE, /* update pending */
+ COMMIT /* beacon sent, commit change */
+ } sc_updateslot; /* slot time update fsm */
+
+ /* Crypto */
+ u32 sc_keymax; /* size of key cache */
+ DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); /* key use bit map */
+ u8 sc_splitmic; /* split TKIP MIC keys */
+ int sc_keytype;
+
+ /* RX */
+ struct list_head sc_rxbuf;
+ struct ath_descdma sc_rxdma;
+ int sc_rxbufsize; /* rx size based on mtu */
+ u32 *sc_rxlink; /* link ptr in last RX desc */
+ u32 sc_rxflush; /* rx flush in progress */
+ u64 sc_lastrx; /* tsf of last rx'd frame */
+
+ /* TX */
+ struct list_head sc_txbuf;
+ struct ath_txq sc_txq[ATH9K_NUM_TX_QUEUES];
+ struct ath_descdma sc_txdma;
+ u32 sc_txqsetup;
+ u32 sc_txintrperiod; /* tx interrupt batching */
+ int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */
+ u32 sc_ant_tx[8]; /* recent tx frames/antenna */
+ u16 seq_no; /* TX sequence number */
+
+ /* Beacon */
+ struct ath9k_tx_queue_info sc_beacon_qi;
+ struct ath_descdma sc_bdma;
+ struct ath_txq *sc_cabq;
+ struct list_head sc_bbuf;
+ u32 sc_bhalq;
+ u32 sc_bmisscount;
+ u32 ast_be_xmit; /* beacons transmitted */
+
+ /* Rate */
+ struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
+ const struct ath9k_rate_table *sc_currates;
+ u8 sc_rixmap[256]; /* IEEE to h/w rate table ix */
+ u8 sc_protrix; /* protection rate index */
+ struct {
+ u32 rateKbps; /* transfer rate in kbs */
+ u8 ieeerate; /* IEEE rate */
+ } sc_hwmap[256]; /* h/w rate ix mappings */
+
+ /* Channel, Band */
+ struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX];
+ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
+ struct ath9k_channel sc_curchan;
+
+ /* Locks */
+ spinlock_t sc_rxflushlock;
+ spinlock_t sc_rxbuflock;
+ spinlock_t sc_txbuflock;
+ spinlock_t sc_resetlock;
+ spinlock_t node_lock;
+};
+
+int ath_init(u16 devid, struct ath_softc *sc);
+void ath_deinit(struct ath_softc *sc);
+int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan);
+int ath_suspend(struct ath_softc *sc);
+irqreturn_t ath_isr(int irq, void *dev);
+int ath_reset(struct ath_softc *sc);
+void ath_scan_start(struct ath_softc *sc);
+void ath_scan_end(struct ath_softc *sc);
+int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan);
+void ath_setup_rate(struct ath_softc *sc,
+ enum wireless_mode wMode,
+ enum RATE_TYPE type,
+ const struct ath9k_rate_table *rt);
+
+/*********************/
+/* Utility Functions */
+/*********************/
+
+void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot);
+int ath_keyset(struct ath_softc *sc,
+ u16 keyix,
+ struct ath9k_keyval *hk,
+ const u8 mac[ETH_ALEN]);
+int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
+int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
+void ath_setslottime(struct ath_softc *sc);
+void ath_update_txpow(struct ath_softc *sc);
+int ath_cabq_update(struct ath_softc *);
+void ath_get_currentCountry(struct ath_softc *sc,
+ struct ath9k_country_entry *ctry);
+u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp);
+void ath_internal_reset(struct ath_softc *sc);
+u32 ath_chan2flags(struct ieee80211_channel *chan, struct ath_softc *sc);
+dma_addr_t ath_skb_map_single(struct ath_softc *sc,
+ struct sk_buff *skb,
+ int direction,
+ dma_addr_t *pa);
+void ath_skb_unmap_single(struct ath_softc *sc,
+ struct sk_buff *skb,
+ int direction,
+ dma_addr_t *pa);
+void ath_mcast_merge(struct ath_softc *sc, u32 mfilt[2]);
+enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc);
+
+#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
new file mode 100644
index 00000000000..6dbfed0b414
--- /dev/null
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -0,0 +1,8575 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/io.h>
+#include <asm/unaligned.h>
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+#include "initvals.h"
+
+static void ath9k_hw_iqcal_collect(struct ath_hal *ah);
+static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains);
+static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah);
+static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah,
+ u8 numChains);
+static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah);
+static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah,
+ u8 numChains);
+
+static const u8 CLOCK_RATE[] = { 40, 80, 22, 44, 88, 40 };
+static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 };
+
+static const struct hal_percal_data iq_cal_multi_sample = {
+ IQ_MISMATCH_CAL,
+ MAX_CAL_SAMPLES,
+ PER_MIN_LOG_COUNT,
+ ath9k_hw_iqcal_collect,
+ ath9k_hw_iqcalibrate
+};
+static const struct hal_percal_data iq_cal_single_sample = {
+ IQ_MISMATCH_CAL,
+ MIN_CAL_SAMPLES,
+ PER_MAX_LOG_COUNT,
+ ath9k_hw_iqcal_collect,
+ ath9k_hw_iqcalibrate
+};
+static const struct hal_percal_data adc_gain_cal_multi_sample = {
+ ADC_GAIN_CAL,
+ MAX_CAL_SAMPLES,
+ PER_MIN_LOG_COUNT,
+ ath9k_hw_adc_gaincal_collect,
+ ath9k_hw_adc_gaincal_calibrate
+};
+static const struct hal_percal_data adc_gain_cal_single_sample = {
+ ADC_GAIN_CAL,
+ MIN_CAL_SAMPLES,
+ PER_MAX_LOG_COUNT,
+ ath9k_hw_adc_gaincal_collect,
+ ath9k_hw_adc_gaincal_calibrate
+};
+static const struct hal_percal_data adc_dc_cal_multi_sample = {
+ ADC_DC_CAL,
+ MAX_CAL_SAMPLES,
+ PER_MIN_LOG_COUNT,
+ ath9k_hw_adc_dccal_collect,
+ ath9k_hw_adc_dccal_calibrate
+};
+static const struct hal_percal_data adc_dc_cal_single_sample = {
+ ADC_DC_CAL,
+ MIN_CAL_SAMPLES,
+ PER_MAX_LOG_COUNT,
+ ath9k_hw_adc_dccal_collect,
+ ath9k_hw_adc_dccal_calibrate
+};
+static const struct hal_percal_data adc_init_dc_cal = {
+ ADC_DC_INIT_CAL,
+ MIN_CAL_SAMPLES,
+ INIT_LOG_COUNT,
+ ath9k_hw_adc_dccal_collect,
+ ath9k_hw_adc_dccal_calibrate
+};
+
+static const struct ath_hal ar5416hal = {
+ AR5416_MAGIC,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ CTRY_DEFAULT,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+};
+
+static struct ath9k_rate_table ar5416_11a_table = {
+ 8,
+ {0},
+ {
+ {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
+ {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
+ {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
+ {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
+ {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
+ {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
+ {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
+ {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}
+ },
+};
+
+static struct ath9k_rate_table ar5416_11b_table = {
+ 4,
+ {0},
+ {
+ {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
+ {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
+ {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1},
+ {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1}
+ },
+};
+
+static struct ath9k_rate_table ar5416_11g_table = {
+ 12,
+ {0},
+ {
+ {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
+ {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
+ {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
+ {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
+
+ {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
+ {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
+ {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
+ {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
+ {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
+ {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
+ {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
+ {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}
+ },
+};
+
+static struct ath9k_rate_table ar5416_11ng_table = {
+ 28,
+ {0},
+ {
+ {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0},
+ {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1},
+ {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2},
+ {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3},
+
+ {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4},
+ {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4},
+ {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6},
+ {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6},
+ {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8},
+ {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8},
+ {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8},
+ {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8},
+ {true, PHY_HT, 6500, 0x80, 0x00, 0, 4},
+ {true, PHY_HT, 13000, 0x81, 0x00, 1, 6},
+ {true, PHY_HT, 19500, 0x82, 0x00, 2, 6},
+ {true, PHY_HT, 26000, 0x83, 0x00, 3, 8},
+ {true, PHY_HT, 39000, 0x84, 0x00, 4, 8},
+ {true, PHY_HT, 52000, 0x85, 0x00, 5, 8},
+ {true, PHY_HT, 58500, 0x86, 0x00, 6, 8},
+ {true, PHY_HT, 65000, 0x87, 0x00, 7, 8},
+ {true, PHY_HT, 13000, 0x88, 0x00, 8, 4},
+ {true, PHY_HT, 26000, 0x89, 0x00, 9, 6},
+ {true, PHY_HT, 39000, 0x8a, 0x00, 10, 6},
+ {true, PHY_HT, 52000, 0x8b, 0x00, 11, 8},
+ {true, PHY_HT, 78000, 0x8c, 0x00, 12, 8},
+ {true, PHY_HT, 104000, 0x8d, 0x00, 13, 8},
+ {true, PHY_HT, 117000, 0x8e, 0x00, 14, 8},
+ {true, PHY_HT, 130000, 0x8f, 0x00, 15, 8},
+ },
+};
+
+static struct ath9k_rate_table ar5416_11na_table = {
+ 24,
+ {0},
+ {
+ {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0},
+ {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0},
+ {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2},
+ {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2},
+ {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4},
+ {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4},
+ {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4},
+ {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4},
+ {true, PHY_HT, 6500, 0x80, 0x00, 0, 0},
+ {true, PHY_HT, 13000, 0x81, 0x00, 1, 2},
+ {true, PHY_HT, 19500, 0x82, 0x00, 2, 2},
+ {true, PHY_HT, 26000, 0x83, 0x00, 3, 4},
+ {true, PHY_HT, 39000, 0x84, 0x00, 4, 4},
+ {true, PHY_HT, 52000, 0x85, 0x00, 5, 4},
+ {true, PHY_HT, 58500, 0x86, 0x00, 6, 4},
+ {true, PHY_HT, 65000, 0x87, 0x00, 7, 4},
+ {true, PHY_HT, 13000, 0x88, 0x00, 8, 0},
+ {true, PHY_HT, 26000, 0x89, 0x00, 9, 2},
+ {true, PHY_HT, 39000, 0x8a, 0x00, 10, 2},
+ {true, PHY_HT, 52000, 0x8b, 0x00, 11, 4},
+ {true, PHY_HT, 78000, 0x8c, 0x00, 12, 4},
+ {true, PHY_HT, 104000, 0x8d, 0x00, 13, 4},
+ {true, PHY_HT, 117000, 0x8e, 0x00, 14, 4},
+ {true, PHY_HT, 130000, 0x8f, 0x00, 15, 4},
+ },
+};
+
+static enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah,
+ const struct ath9k_channel *chan)
+{
+ if (IS_CHAN_CCK(chan))
+ return ATH9K_MODE_11A;
+ if (IS_CHAN_G(chan))
+ return ATH9K_MODE_11G;
+ return ATH9K_MODE_11A;
+}
+
+static bool ath9k_hw_wait(struct ath_hal *ah,
+ u32 reg,
+ u32 mask,
+ u32 val)
+{
+ int i;
+
+ for (i = 0; i < (AH_TIMEOUT / AH_TIME_QUANTUM); i++) {
+ if ((REG_READ(ah, reg) & mask) == val)
+ return true;
+
+ udelay(AH_TIME_QUANTUM);
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
+ "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
+ __func__, reg, REG_READ(ah, reg), mask, val);
+ return false;
+}
+
+static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off,
+ u16 *data)
+{
+ (void) REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
+
+ if (!ath9k_hw_wait(ah,
+ AR_EEPROM_STATUS_DATA,
+ AR_EEPROM_STATUS_DATA_BUSY |
+ AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
+ return false;
+ }
+
+ *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
+ AR_EEPROM_STATUS_DATA_VAL);
+
+ return true;
+}
+
+static int ath9k_hw_flash_map(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX);
+
+ if (!ahp->ah_cal_mem) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "%s: cannot remap eeprom region \n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off,
+ u16 *data)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ *data = ioread16(ahp->ah_cal_mem + off);
+ return true;
+}
+
+static void ath9k_hw_read_revisions(struct ath_hal *ah)
+{
+ u32 val;
+
+ val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
+
+ if (val == 0xFF) {
+ val = REG_READ(ah, AR_SREV);
+
+ ah->ah_macVersion =
+ (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
+
+ ah->ah_macRev = MS(val, AR_SREV_REVISION2);
+ ah->ah_isPciExpress =
+ (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1;
+
+ } else {
+ if (!AR_SREV_9100(ah))
+ ah->ah_macVersion = MS(val, AR_SREV_VERSION);
+
+ ah->ah_macRev = val & AR_SREV_REVISION;
+
+ if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE)
+ ah->ah_isPciExpress = true;
+ }
+}
+
+u32 ath9k_hw_reverse_bits(u32 val, u32 n)
+{
+ u32 retval;
+ int i;
+
+ for (i = 0, retval = 0; i < n; i++) {
+ retval = (retval << 1) | (val & 1);
+ val >>= 1;
+ }
+ return retval;
+}
+
+static void ath9k_hw_set_defaults(struct ath_hal *ah)
+{
+ int i;
+
+ ah->ah_config.dma_beacon_response_time = 2;
+ ah->ah_config.sw_beacon_response_time = 10;
+ ah->ah_config.additional_swba_backoff = 0;
+ ah->ah_config.ack_6mb = 0x0;
+ ah->ah_config.cwm_ignore_extcca = 0;
+ ah->ah_config.pcie_powersave_enable = 0;
+ ah->ah_config.pcie_l1skp_enable = 0;
+ ah->ah_config.pcie_clock_req = 0;
+ ah->ah_config.pcie_power_reset = 0x100;
+ ah->ah_config.pcie_restore = 0;
+ ah->ah_config.pcie_waen = 0;
+ ah->ah_config.analog_shiftreg = 1;
+ ah->ah_config.ht_enable = 1;
+ ah->ah_config.ofdm_trig_low = 200;
+ ah->ah_config.ofdm_trig_high = 500;
+ ah->ah_config.cck_trig_high = 200;
+ ah->ah_config.cck_trig_low = 100;
+ ah->ah_config.enable_ani = 0;
+ ah->ah_config.noise_immunity_level = 4;
+ ah->ah_config.ofdm_weaksignal_det = 1;
+ ah->ah_config.cck_weaksignal_thr = 0;
+ ah->ah_config.spur_immunity_level = 2;
+ ah->ah_config.firstep_level = 0;
+ ah->ah_config.rssi_thr_high = 40;
+ ah->ah_config.rssi_thr_low = 7;
+ ah->ah_config.diversity_control = 0;
+ ah->ah_config.antenna_switch_swap = 0;
+
+ for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+ ah->ah_config.spurchans[i][0] = AR_NO_SPUR;
+ ah->ah_config.spurchans[i][1] = AR_NO_SPUR;
+ }
+
+ ah->ah_config.intr_mitigation = 0;
+}
+
+static inline void ath9k_hw_override_ini(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ if (!AR_SREV_5416_V20_OR_LATER(ah)
+ || AR_SREV_9280_10_OR_LATER(ah))
+ return;
+
+ REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
+}
+
+static inline void ath9k_hw_init_bb(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ u32 synthDelay;
+
+ synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+ if (IS_CHAN_CCK(chan))
+ synthDelay = (4 * synthDelay) / 22;
+ else
+ synthDelay /= 10;
+
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+ udelay(synthDelay + BASE_ACTIVATE_DELAY);
+}
+
+static inline void ath9k_hw_init_interrupt_masks(struct ath_hal *ah,
+ enum ath9k_opmode opmode)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ ahp->ah_maskReg = AR_IMR_TXERR |
+ AR_IMR_TXURN |
+ AR_IMR_RXERR |
+ AR_IMR_RXORN |
+ AR_IMR_BCNMISC;
+
+ if (ahp->ah_intrMitigation)
+ ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
+ else
+ ahp->ah_maskReg |= AR_IMR_RXOK;
+
+ ahp->ah_maskReg |= AR_IMR_TXOK;
+
+ if (opmode == ATH9K_M_HOSTAP)
+ ahp->ah_maskReg |= AR_IMR_MIB;
+
+ REG_WRITE(ah, AR_IMR, ahp->ah_maskReg);
+ REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
+
+ if (!AR_SREV_9100(ah)) {
+ REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
+ REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
+ }
+}
+
+static inline void ath9k_hw_init_qos(struct ath_hal *ah)
+{
+ REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
+ REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
+
+ REG_WRITE(ah, AR_QOS_NO_ACK,
+ SM(2, AR_QOS_NO_ACK_TWO_BIT) |
+ SM(5, AR_QOS_NO_ACK_BIT_OFF) |
+ SM(0, AR_QOS_NO_ACK_BYTE_OFF));
+
+ REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL);
+ REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
+ REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
+}
+
+static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah,
+ u32 reg,
+ u32 mask,
+ u32 shift,
+ u32 val)
+{
+ u32 regVal;
+
+ regVal = REG_READ(ah, reg) & ~mask;
+ regVal |= (val << shift) & mask;
+
+ REG_WRITE(ah, reg, regVal);
+
+ if (ah->ah_config.analog_shiftreg)
+ udelay(100);
+
+ return;
+}
+
+static u8 ath9k_hw_get_num_ant_config(struct ath_hal_5416 *ahp,
+ enum ieee80211_band freq_band)
+{
+ struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+ struct modal_eep_header *pModal =
+ &(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]);
+ struct base_eep_header *pBase = &eep->baseEepHeader;
+ u8 num_ant_config;
+
+ num_ant_config = 1;
+
+ if (pBase->version >= 0x0E0D)
+ if (pModal->useAnt1)
+ num_ant_config += 1;
+
+ return num_ant_config;
+}
+
+static int
+ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal_5416 *ahp,
+ struct ath9k_channel *chan,
+ u8 index,
+ u16 *config)
+{
+ struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+ struct modal_eep_header *pModal =
+ &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+ struct base_eep_header *pBase = &eep->baseEepHeader;
+
+ switch (index) {
+ case 0:
+ *config = pModal->antCtrlCommon & 0xFFFF;
+ return 0;
+ case 1:
+ if (pBase->version >= 0x0E0D) {
+ if (pModal->useAnt1) {
+ *config =
+ ((pModal->antCtrlCommon & 0xFFFF0000) >> 16);
+ return 0;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static inline bool ath9k_hw_nvram_read(struct ath_hal *ah,
+ u32 off,
+ u16 *data)
+{
+ if (ath9k_hw_use_flash(ah))
+ return ath9k_hw_flash_read(ah, off, data);
+ else
+ return ath9k_hw_eeprom_read(ah, off, data);
+}
+
+static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+ u16 *eep_data;
+ int addr, ar5416_eep_start_loc = 0;
+
+ if (!ath9k_hw_use_flash(ah)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "%s: Reading from EEPROM, not flash\n", __func__);
+ ar5416_eep_start_loc = 256;
+ }
+ if (AR_SREV_9100(ah))
+ ar5416_eep_start_loc = 256;
+
+ eep_data = (u16 *) eep;
+ for (addr = 0;
+ addr < sizeof(struct ar5416_eeprom) / sizeof(u16);
+ addr++) {
+ if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc,
+ eep_data)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "%s: Unable to read eeprom region \n",
+ __func__);
+ return false;
+ }
+ eep_data++;
+ }
+ return true;
+}
+
+/* XXX: Clean me up, make me more legible */
+static bool
+ath9k_hw_eeprom_set_board_values(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct modal_eep_header *pModal;
+ int i, regChainOffset;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+ u8 txRxAttenLocal;
+ u16 ant_config;
+
+ pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+ txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44;
+
+ ath9k_hw_get_eeprom_antenna_cfg(ahp, chan, 1, &ant_config);
+ REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ if (AR_SREV_9280(ah)) {
+ if (i >= 2)
+ break;
+ }
+
+ if (AR_SREV_5416_V20_OR_LATER(ah) &&
+ (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
+ && (i != 0))
+ regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+ else
+ regChainOffset = i * 0x1000;
+
+ REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
+ pModal->antCtrlChain[i]);
+
+ REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
+ (REG_READ(ah,
+ AR_PHY_TIMING_CTRL4(0) +
+ regChainOffset) &
+ ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
+ SM(pModal->iqCalICh[i],
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
+ SM(pModal->iqCalQCh[i],
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
+
+ if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+ if ((eep->baseEepHeader.version &
+ AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_3) {
+ txRxAttenLocal = pModal->txRxAttenCh[i];
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ REG_RMW_FIELD(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+ pModal->
+ bswMargin[i]);
+ REG_RMW_FIELD(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB,
+ pModal->
+ bswAtten[i]);
+ REG_RMW_FIELD(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+ pModal->
+ xatten2Margin[i]);
+ REG_RMW_FIELD(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+ pModal->
+ xatten2Db[i]);
+ } else {
+ REG_WRITE(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ (REG_READ(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset) &
+ ~AR_PHY_GAIN_2GHZ_BSW_MARGIN)
+ | SM(pModal->
+ bswMargin[i],
+ AR_PHY_GAIN_2GHZ_BSW_MARGIN));
+ REG_WRITE(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ (REG_READ(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset) &
+ ~AR_PHY_GAIN_2GHZ_BSW_ATTEN)
+ | SM(pModal->bswAtten[i],
+ AR_PHY_GAIN_2GHZ_BSW_ATTEN));
+ }
+ }
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ REG_RMW_FIELD(ah,
+ AR_PHY_RXGAIN +
+ regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN,
+ txRxAttenLocal);
+ REG_RMW_FIELD(ah,
+ AR_PHY_RXGAIN +
+ regChainOffset,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN,
+ pModal->rxTxMarginCh[i]);
+ } else {
+ REG_WRITE(ah,
+ AR_PHY_RXGAIN + regChainOffset,
+ (REG_READ(ah,
+ AR_PHY_RXGAIN +
+ regChainOffset) &
+ ~AR_PHY_RXGAIN_TXRX_ATTEN) |
+ SM(txRxAttenLocal,
+ AR_PHY_RXGAIN_TXRX_ATTEN));
+ REG_WRITE(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset,
+ (REG_READ(ah,
+ AR_PHY_GAIN_2GHZ +
+ regChainOffset) &
+ ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) |
+ SM(pModal->rxTxMarginCh[i],
+ AR_PHY_GAIN_2GHZ_RXTX_MARGIN));
+ }
+ }
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (IS_CHAN_2GHZ(chan)) {
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+ AR_AN_RF2G1_CH0_OB,
+ AR_AN_RF2G1_CH0_OB_S,
+ pModal->ob);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0,
+ AR_AN_RF2G1_CH0_DB,
+ AR_AN_RF2G1_CH0_DB_S,
+ pModal->db);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+ AR_AN_RF2G1_CH1_OB,
+ AR_AN_RF2G1_CH1_OB_S,
+ pModal->ob_ch1);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1,
+ AR_AN_RF2G1_CH1_DB,
+ AR_AN_RF2G1_CH1_DB_S,
+ pModal->db_ch1);
+ } else {
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+ AR_AN_RF5G1_CH0_OB5,
+ AR_AN_RF5G1_CH0_OB5_S,
+ pModal->ob);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0,
+ AR_AN_RF5G1_CH0_DB5,
+ AR_AN_RF5G1_CH0_DB5_S,
+ pModal->db);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+ AR_AN_RF5G1_CH1_OB5,
+ AR_AN_RF5G1_CH1_OB5_S,
+ pModal->ob_ch1);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1,
+ AR_AN_RF5G1_CH1_DB5,
+ AR_AN_RF5G1_CH1_DB5_S,
+ pModal->db_ch1);
+ }
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+ AR_AN_TOP2_XPABIAS_LVL,
+ AR_AN_TOP2_XPABIAS_LVL_S,
+ pModal->xpaBiasLvl);
+ ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
+ AR_AN_TOP2_LOCALBIAS,
+ AR_AN_TOP2_LOCALBIAS_S,
+ pModal->local_bias);
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY, "ForceXPAon: %d\n",
+ pModal->force_xpaon);
+ REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
+ pModal->force_xpaon);
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
+ pModal->switchSettling);
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC,
+ pModal->adcDesiredSize);
+
+ if (!AR_SREV_9280_10_OR_LATER(ah))
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+ AR_PHY_DESIRED_SZ_PGA,
+ pModal->pgaDesiredSize);
+
+ REG_WRITE(ah, AR_PHY_RF_CTL4,
+ SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
+ | SM(pModal->txEndToXpaOff,
+ AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
+ | SM(pModal->txFrameToXpaOn,
+ AR_PHY_RF_CTL4_FRAME_XPAA_ON)
+ | SM(pModal->txFrameToXpaOn,
+ AR_PHY_RF_CTL4_FRAME_XPAB_ON));
+
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON,
+ pModal->txEndToRxOn);
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62,
+ pModal->thresh62);
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
+ AR_PHY_EXT_CCA0_THRESH62,
+ pModal->thresh62);
+ } else {
+ REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62,
+ pModal->thresh62);
+ REG_RMW_FIELD(ah, AR_PHY_EXT_CCA,
+ AR_PHY_EXT_CCA_THRESH62,
+ pModal->thresh62);
+ }
+
+ if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
+ AR_PHY_TX_END_DATA_START,
+ pModal->txFrameToDataStart);
+ REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON,
+ pModal->txFrameToPaOn);
+ }
+
+ if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_3) {
+ if (IS_CHAN_HT40(chan))
+ REG_RMW_FIELD(ah, AR_PHY_SETTLING,
+ AR_PHY_SETTLING_SWITCH,
+ pModal->swSettleHt40);
+ }
+
+ return true;
+}
+
+static inline int ath9k_hw_check_eeprom(struct ath_hal *ah)
+{
+ u32 sum = 0, el;
+ u16 *eepdata;
+ int i;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ bool need_swap = false;
+ struct ar5416_eeprom *eep =
+ (struct ar5416_eeprom *) &ahp->ah_eeprom;
+
+ if (!ath9k_hw_use_flash(ah)) {
+ u16 magic, magic2;
+ int addr;
+
+ if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET,
+ &magic)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "%s: Reading Magic # failed\n", __func__);
+ return false;
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n",
+ __func__, magic);
+
+ if (magic != AR5416_EEPROM_MAGIC) {
+ magic2 = swab16(magic);
+
+ if (magic2 == AR5416_EEPROM_MAGIC) {
+ need_swap = true;
+ eepdata = (u16 *) (&ahp->ah_eeprom);
+
+ for (addr = 0;
+ addr <
+ sizeof(struct ar5416_eeprom) /
+ sizeof(u16); addr++) {
+ u16 temp;
+
+ temp = swab16(*eepdata);
+ *eepdata = temp;
+ eepdata++;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "0x%04X ", *eepdata);
+ if (((addr + 1) % 6) == 0)
+ DPRINTF(ah->ah_sc,
+ ATH_DBG_EEPROM,
+ "\n");
+ }
+ } else {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Invalid EEPROM Magic. "
+ "endianness missmatch.\n");
+ return -EINVAL;
+ }
+ }
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
+
+ if (need_swap)
+ el = swab16(ahp->ah_eeprom.baseEepHeader.length);
+ else
+ el = ahp->ah_eeprom.baseEepHeader.length;
+
+ if (el > sizeof(struct ar5416_eeprom))
+ el = sizeof(struct ar5416_eeprom) / sizeof(u16);
+ else
+ el = el / sizeof(u16);
+
+ eepdata = (u16 *) (&ahp->ah_eeprom);
+
+ for (i = 0; i < el; i++)
+ sum ^= *eepdata++;
+
+ if (need_swap) {
+ u32 integer, j;
+ u16 word;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "EEPROM Endianness is not native.. Changing \n");
+
+ word = swab16(eep->baseEepHeader.length);
+ eep->baseEepHeader.length = word;
+
+ word = swab16(eep->baseEepHeader.checksum);
+ eep->baseEepHeader.checksum = word;
+
+ word = swab16(eep->baseEepHeader.version);
+ eep->baseEepHeader.version = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[0]);
+ eep->baseEepHeader.regDmn[0] = word;
+
+ word = swab16(eep->baseEepHeader.regDmn[1]);
+ eep->baseEepHeader.regDmn[1] = word;
+
+ word = swab16(eep->baseEepHeader.rfSilent);
+ eep->baseEepHeader.rfSilent = word;
+
+ word = swab16(eep->baseEepHeader.blueToothOptions);
+ eep->baseEepHeader.blueToothOptions = word;
+
+ word = swab16(eep->baseEepHeader.deviceCap);
+ eep->baseEepHeader.deviceCap = word;
+
+ for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) {
+ struct modal_eep_header *pModal =
+ &eep->modalHeader[j];
+ integer = swab32(pModal->antCtrlCommon);
+ pModal->antCtrlCommon = integer;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ integer = swab32(pModal->antCtrlChain[i]);
+ pModal->antCtrlChain[i] = integer;
+ }
+
+ for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) {
+ word = swab16(pModal->spurChans[i].spurChan);
+ pModal->spurChans[i].spurChan = word;
+ }
+ }
+ }
+
+ if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER ||
+ ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "Bad EEPROM checksum 0x%x or revision 0x%04x\n",
+ sum, ar5416_get_eep_ver(ahp));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static bool ath9k_hw_chip_test(struct ath_hal *ah)
+{
+ u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) };
+ u32 regHold[2];
+ u32 patternData[4] = { 0x55555555,
+ 0xaaaaaaaa,
+ 0x66666666,
+ 0x99999999 };
+ int i, j;
+
+ for (i = 0; i < 2; i++) {
+ u32 addr = regAddr[i];
+ u32 wrData, rdData;
+
+ regHold[i] = REG_READ(ah, addr);
+ for (j = 0; j < 0x100; j++) {
+ wrData = (j << 16) | j;
+ REG_WRITE(ah, addr, wrData);
+ rdData = REG_READ(ah, addr);
+ if (rdData != wrData) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "%s: address test failed "
+ "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+ __func__, addr, wrData, rdData);
+ return false;
+ }
+ }
+ for (j = 0; j < 4; j++) {
+ wrData = patternData[j];
+ REG_WRITE(ah, addr, wrData);
+ rdData = REG_READ(ah, addr);
+ if (wrData != rdData) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "%s: address test failed "
+ "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n",
+ __func__, addr, wrData, rdData);
+ return false;
+ }
+ }
+ REG_WRITE(ah, regAddr[i], regHold[i]);
+ }
+ udelay(100);
+ return true;
+}
+
+u32 ath9k_hw_getrxfilter(struct ath_hal *ah)
+{
+ u32 bits = REG_READ(ah, AR_RX_FILTER);
+ u32 phybits = REG_READ(ah, AR_PHY_ERR);
+
+ if (phybits & AR_PHY_ERR_RADAR)
+ bits |= ATH9K_RX_FILTER_PHYRADAR;
+ if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING))
+ bits |= ATH9K_RX_FILTER_PHYERR;
+ return bits;
+}
+
+void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits)
+{
+ u32 phybits;
+
+ REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR);
+ phybits = 0;
+ if (bits & ATH9K_RX_FILTER_PHYRADAR)
+ phybits |= AR_PHY_ERR_RADAR;
+ if (bits & ATH9K_RX_FILTER_PHYERR)
+ phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING;
+ REG_WRITE(ah, AR_PHY_ERR, phybits);
+
+ if (phybits)
+ REG_WRITE(ah, AR_RXCFG,
+ REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
+ else
+ REG_WRITE(ah, AR_RXCFG,
+ REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
+}
+
+bool ath9k_hw_setcapability(struct ath_hal *ah,
+ enum ath9k_capability_type type,
+ u32 capability,
+ u32 setting,
+ int *status)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 v;
+
+ switch (type) {
+ case ATH9K_CAP_TKIP_MIC:
+ if (setting)
+ ahp->ah_staId1Defaults |=
+ AR_STA_ID1_CRPT_MIC_ENABLE;
+ else
+ ahp->ah_staId1Defaults &=
+ ~AR_STA_ID1_CRPT_MIC_ENABLE;
+ return true;
+ case ATH9K_CAP_DIVERSITY:
+ v = REG_READ(ah, AR_PHY_CCK_DETECT);
+ if (setting)
+ v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+ else
+ v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+ REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
+ return true;
+ case ATH9K_CAP_MCAST_KEYSRCH:
+ if (setting)
+ ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH;
+ else
+ ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH;
+ return true;
+ case ATH9K_CAP_TSF_ADJUST:
+ if (setting)
+ ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
+ else
+ ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
+ return true;
+ default:
+ return false;
+ }
+}
+
+void ath9k_hw_dmaRegDump(struct ath_hal *ah)
+{
+ u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
+ int qcuOffset = 0, dcuOffset = 0;
+ u32 *qcuBase = &val[0], *dcuBase = &val[4];
+ int i;
+
+ REG_WRITE(ah, AR_MACMISC,
+ ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
+ (AR_MACMISC_MISC_OBS_BUS_1 <<
+ AR_MACMISC_MISC_OBS_BUS_MSB_S)));
+
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n");
+ for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
+ if (i % 4 == 0)
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
+
+ val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32)));
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]);
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
+
+ for (i = 0; i < ATH9K_NUM_QUEUES;
+ i++, qcuOffset += 4, dcuOffset += 5) {
+ if (i == 8) {
+ qcuOffset = 0;
+ qcuBase++;
+ }
+
+ if (i == 6) {
+ dcuOffset = 0;
+ dcuBase++;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "%2d %2x %1x %2x %2x\n",
+ i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
+ (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset +
+ 3),
+ val[2] & (0x7 << (i * 3)) >> (i * 3),
+ (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n");
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "qcu_stitch state: %2x qcu_fetch state: %2x\n",
+ (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "qcu_complete state: %2x dcu_complete state: %2x\n",
+ (val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "dcu_arb state: %2x dcu_fp state: %2x\n",
+ (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n",
+ (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "txfifo_valid_0: %1d txfifo_valid_1: %1d\n",
+ (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n",
+ (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n",
+ REG_READ(ah, AR_OBS_BUS_1));
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "AR_CR 0x%x \n", REG_READ(ah, AR_CR));
+}
+
+u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah,
+ u32 *rxc_pcnt,
+ u32 *rxf_pcnt,
+ u32 *txf_pcnt)
+{
+ static u32 cycles, rx_clear, rx_frame, tx_frame;
+ u32 good = 1;
+
+ u32 rc = REG_READ(ah, AR_RCCNT);
+ u32 rf = REG_READ(ah, AR_RFCNT);
+ u32 tf = REG_READ(ah, AR_TFCNT);
+ u32 cc = REG_READ(ah, AR_CCCNT);
+
+ if (cycles == 0 || cycles > cc) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "%s: cycle counter wrap. ExtBusy = 0\n",
+ __func__);
+ good = 0;
+ } else {
+ u32 cc_d = cc - cycles;
+ u32 rc_d = rc - rx_clear;
+ u32 rf_d = rf - rx_frame;
+ u32 tf_d = tf - tx_frame;
+
+ if (cc_d != 0) {
+ *rxc_pcnt = rc_d * 100 / cc_d;
+ *rxf_pcnt = rf_d * 100 / cc_d;
+ *txf_pcnt = tf_d * 100 / cc_d;
+ } else {
+ good = 0;
+ }
+ }
+
+ cycles = cc;
+ rx_frame = rf;
+ rx_clear = rc;
+ tx_frame = tf;
+
+ return good;
+}
+
+void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode)
+{
+ u32 macmode;
+
+ if (mode == ATH9K_HT_MACMODE_2040 &&
+ !ah->ah_config.cwm_ignore_extcca)
+ macmode = AR_2040_JOINED_RX_CLEAR;
+ else
+ macmode = 0;
+
+ REG_WRITE(ah, AR_2040_MODE, macmode);
+}
+
+static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah)
+{
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+}
+
+
+static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
+ struct ath_softc *sc,
+ void __iomem *mem,
+ int *status)
+{
+ static const u8 defbssidmask[ETH_ALEN] =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ struct ath_hal_5416 *ahp;
+ struct ath_hal *ah;
+
+ ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL);
+ if (ahp == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: cannot allocate memory for state block\n",
+ __func__);
+ *status = -ENOMEM;
+ return NULL;
+ }
+
+ ah = &ahp->ah;
+
+ memcpy(&ahp->ah, &ar5416hal, sizeof(struct ath_hal));
+
+ ah->ah_sc = sc;
+ ah->ah_sh = mem;
+
+ ah->ah_devid = devid;
+ ah->ah_subvendorid = 0;
+
+ ah->ah_flags = 0;
+ if ((devid == AR5416_AR9100_DEVID))
+ ah->ah_macVersion = AR_SREV_VERSION_9100;
+ if (!AR_SREV_9100(ah))
+ ah->ah_flags = AH_USE_EEPROM;
+
+ ah->ah_powerLimit = MAX_RATE_POWER;
+ ah->ah_tpScale = ATH9K_TP_SCALE_MAX;
+
+ ahp->ah_atimWindow = 0;
+ ahp->ah_diversityControl = ah->ah_config.diversity_control;
+ ahp->ah_antennaSwitchSwap =
+ ah->ah_config.antenna_switch_swap;
+
+ ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE;
+ ahp->ah_beaconInterval = 100;
+ ahp->ah_enable32kHzClock = DONT_USE_32KHZ;
+ ahp->ah_slottime = (u32) -1;
+ ahp->ah_acktimeout = (u32) -1;
+ ahp->ah_ctstimeout = (u32) -1;
+ ahp->ah_globaltxtimeout = (u32) -1;
+ memcpy(&ahp->ah_bssidmask, defbssidmask, ETH_ALEN);
+
+ ahp->ah_gBeaconRate = 0;
+
+ return ahp;
+}
+
+static int ath9k_hw_eeprom_attach(struct ath_hal *ah)
+{
+ int status;
+
+ if (ath9k_hw_use_flash(ah))
+ ath9k_hw_flash_map(ah);
+
+ if (!ath9k_hw_fill_eeprom(ah))
+ return -EIO;
+
+ status = ath9k_hw_check_eeprom(ah);
+
+ return status;
+}
+
+u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
+ enum eeprom_param param)
+{
+ struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+ struct modal_eep_header *pModal = eep->modalHeader;
+ struct base_eep_header *pBase = &eep->baseEepHeader;
+
+ switch (param) {
+ case EEP_NFTHRESH_5:
+ return -pModal[0].noiseFloorThreshCh[0];
+ case EEP_NFTHRESH_2:
+ return -pModal[1].noiseFloorThreshCh[0];
+ case AR_EEPROM_MAC(0):
+ return pBase->macAddr[0] << 8 | pBase->macAddr[1];
+ case AR_EEPROM_MAC(1):
+ return pBase->macAddr[2] << 8 | pBase->macAddr[3];
+ case AR_EEPROM_MAC(2):
+ return pBase->macAddr[4] << 8 | pBase->macAddr[5];
+ case EEP_REG_0:
+ return pBase->regDmn[0];
+ case EEP_REG_1:
+ return pBase->regDmn[1];
+ case EEP_OP_CAP:
+ return pBase->deviceCap;
+ case EEP_OP_MODE:
+ return pBase->opCapFlags;
+ case EEP_RF_SILENT:
+ return pBase->rfSilent;
+ case EEP_OB_5:
+ return pModal[0].ob;
+ case EEP_DB_5:
+ return pModal[0].db;
+ case EEP_OB_2:
+ return pModal[1].ob;
+ case EEP_DB_2:
+ return pModal[1].db;
+ case EEP_MINOR_REV:
+ return pBase->version & AR5416_EEP_VER_MINOR_MASK;
+ case EEP_TX_MASK:
+ return pBase->txMask;
+ case EEP_RX_MASK:
+ return pBase->rxMask;
+ default:
+ return 0;
+ }
+}
+
+static inline int ath9k_hw_get_radiorev(struct ath_hal *ah)
+{
+ u32 val;
+ int i;
+
+ REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
+ for (i = 0; i < 8; i++)
+ REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
+ val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
+ val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
+ return ath9k_hw_reverse_bits(val, 8);
+}
+
+static inline int ath9k_hw_init_macaddr(struct ath_hal *ah)
+{
+ u32 sum;
+ int i;
+ u16 eeval;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ DECLARE_MAC_BUF(mac);
+
+ sum = 0;
+ for (i = 0; i < 3; i++) {
+ eeval = ath9k_hw_get_eeprom(ahp, AR_EEPROM_MAC(i));
+ sum += eeval;
+ ahp->ah_macaddr[2 * i] = eeval >> 8;
+ ahp->ah_macaddr[2 * i + 1] = eeval & 0xff;
+ }
+ if (sum == 0 || sum == 0xffff * 3) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "%s: mac address read failed: %s\n", __func__,
+ print_mac(mac, ahp->ah_macaddr));
+ return -EADDRNOTAVAIL;
+ }
+
+ return 0;
+}
+
+static inline int16_t ath9k_hw_interpolate(u16 target,
+ u16 srcLeft,
+ u16 srcRight,
+ int16_t targetLeft,
+ int16_t targetRight)
+{
+ int16_t rv;
+
+ if (srcRight == srcLeft) {
+ rv = targetLeft;
+ } else {
+ rv = (int16_t) (((target - srcLeft) * targetRight +
+ (srcRight - target) * targetLeft) /
+ (srcRight - srcLeft));
+ }
+ return rv;
+}
+
+static inline u16 ath9k_hw_fbin2freq(u8 fbin,
+ bool is2GHz)
+{
+
+ if (fbin == AR5416_BCHAN_UNUSED)
+ return fbin;
+
+ return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
+}
+
+static u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah,
+ u16 i,
+ bool is2GHz)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom *eep =
+ (struct ar5416_eeprom *) &ahp->ah_eeprom;
+ u16 spur_val = AR_NO_SPUR;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Getting spur idx %d is2Ghz. %d val %x\n",
+ i, is2GHz, ah->ah_config.spurchans[i][is2GHz]);
+
+ switch (ah->ah_config.spurmode) {
+ case SPUR_DISABLE:
+ break;
+ case SPUR_ENABLE_IOCTL:
+ spur_val = ah->ah_config.spurchans[i][is2GHz];
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Getting spur val from new loc. %d\n", spur_val);
+ break;
+ case SPUR_ENABLE_EEPROM:
+ spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan;
+ break;
+
+ }
+ return spur_val;
+}
+
+static inline int ath9k_hw_rfattach(struct ath_hal *ah)
+{
+ bool rfStatus = false;
+ int ecode = 0;
+
+ rfStatus = ath9k_hw_init_rf(ah, &ecode);
+ if (!rfStatus) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "%s: RF setup failed, status %u\n", __func__,
+ ecode);
+ return ecode;
+ }
+
+ return 0;
+}
+
+static int ath9k_hw_rf_claim(struct ath_hal *ah)
+{
+ u32 val;
+
+ REG_WRITE(ah, AR_PHY(0), 0x00000007);
+
+ val = ath9k_hw_get_radiorev(ah);
+ switch (val & AR_RADIO_SREV_MAJOR) {
+ case 0:
+ val = AR_RAD5133_SREV_MAJOR;
+ break;
+ case AR_RAD5133_SREV_MAJOR:
+ case AR_RAD5122_SREV_MAJOR:
+ case AR_RAD2133_SREV_MAJOR:
+ case AR_RAD2122_SREV_MAJOR:
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "%s: 5G Radio Chip Rev 0x%02X is not "
+ "supported by this driver\n",
+ __func__, ah->ah_analog5GhzRev);
+ return -EOPNOTSUPP;
+ }
+
+ ah->ah_analog5GhzRev = val;
+
+ return 0;
+}
+
+static inline void ath9k_hw_init_pll(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ u32 pll;
+
+ if (AR_SREV_9100(ah)) {
+ if (chan && IS_CHAN_5GHZ(chan))
+ pll = 0x1450;
+ else
+ pll = 0x1458;
+ } else {
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
+
+ if (chan && IS_CHAN_HALF_RATE(chan))
+ pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+ else if (chan && IS_CHAN_QUARTER_RATE(chan))
+ pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
+
+ if (chan && IS_CHAN_5GHZ(chan)) {
+ pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
+
+
+ if (AR_SREV_9280_20(ah)) {
+ if (((chan->channel % 20) == 0)
+ || ((chan->channel % 10) == 0))
+ pll = 0x2850;
+ else
+ pll = 0x142c;
+ }
+ } else {
+ pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
+ }
+
+ } else if (AR_SREV_9160_10_OR_LATER(ah)) {
+
+ pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
+
+ if (chan && IS_CHAN_HALF_RATE(chan))
+ pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+ else if (chan && IS_CHAN_QUARTER_RATE(chan))
+ pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
+
+ if (chan && IS_CHAN_5GHZ(chan))
+ pll |= SM(0x50, AR_RTC_9160_PLL_DIV);
+ else
+ pll |= SM(0x58, AR_RTC_9160_PLL_DIV);
+ } else {
+ pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
+
+ if (chan && IS_CHAN_HALF_RATE(chan))
+ pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
+ else if (chan && IS_CHAN_QUARTER_RATE(chan))
+ pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
+
+ if (chan && IS_CHAN_5GHZ(chan))
+ pll |= SM(0xa, AR_RTC_PLL_DIV);
+ else
+ pll |= SM(0xb, AR_RTC_PLL_DIV);
+ }
+ }
+ REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll);
+
+ udelay(RTC_PLL_SETTLE_DELAY);
+
+ REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
+}
+
+static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
+ enum ath9k_ht_macmode macmode)
+{
+ u32 phymode;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
+ | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH;
+
+ if (IS_CHAN_HT40(chan)) {
+ phymode |= AR_PHY_FC_DYN2040_EN;
+
+ if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+ (chan->chanmode == CHANNEL_G_HT40PLUS))
+ phymode |= AR_PHY_FC_DYN2040_PRI_CH;
+
+ if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25)
+ phymode |= AR_PHY_FC_DYN2040_EXT_CH;
+ }
+ REG_WRITE(ah, AR_PHY_TURBO, phymode);
+
+ ath9k_hw_set11nmac2040(ah, macmode);
+
+ REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
+ REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
+}
+
+static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode)
+{
+ u32 val;
+
+ val = REG_READ(ah, AR_STA_ID1);
+ val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);
+ switch (opmode) {
+ case ATH9K_M_HOSTAP:
+ REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP
+ | AR_STA_ID1_KSRCH_MODE);
+ REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
+ break;
+ case ATH9K_M_IBSS:
+ REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC
+ | AR_STA_ID1_KSRCH_MODE);
+ REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
+ break;
+ case ATH9K_M_STA:
+ case ATH9K_M_MONITOR:
+ REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
+ break;
+ }
+}
+
+static inline void
+ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+ u32 rfMode = 0;
+
+ if (chan == NULL)
+ return;
+
+ rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
+ ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
+
+ if (!AR_SREV_9280_10_OR_LATER(ah))
+ rfMode |= (IS_CHAN_5GHZ(chan)) ? AR_PHY_MODE_RF5GHZ :
+ AR_PHY_MODE_RF2GHZ;
+
+ if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan))
+ rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
+
+ REG_WRITE(ah, AR_PHY_MODE, rfMode);
+}
+
+static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
+{
+ u32 rst_flags;
+ u32 tmpReg;
+
+ REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
+ AR_RTC_FORCE_WAKE_ON_INT);
+
+ if (AR_SREV_9100(ah)) {
+ rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD |
+ AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET;
+ } else {
+ tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE);
+ if (tmpReg &
+ (AR_INTR_SYNC_LOCAL_TIMEOUT |
+ AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
+ REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
+ REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+ } else {
+ REG_WRITE(ah, AR_RC, AR_RC_AHB);
+ }
+
+ rst_flags = AR_RTC_RC_MAC_WARM;
+ if (type == ATH9K_RESET_COLD)
+ rst_flags |= AR_RTC_RC_MAC_COLD;
+ }
+
+ REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags);
+ udelay(50);
+
+ REG_WRITE(ah, (u16) (AR_RTC_RC), 0);
+ if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "%s: RTC stuck in MAC reset\n",
+ __func__);
+ return false;
+ }
+
+ if (!AR_SREV_9100(ah))
+ REG_WRITE(ah, AR_RC, 0);
+
+ ath9k_hw_init_pll(ah, NULL);
+
+ if (AR_SREV_9100(ah))
+ udelay(50);
+
+ return true;
+}
+
+static inline bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
+{
+ REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
+ AR_RTC_FORCE_WAKE_ON_INT);
+
+ REG_WRITE(ah, (u16) (AR_RTC_RESET), 0);
+ REG_WRITE(ah, (u16) (AR_RTC_RESET), 1);
+
+ if (!ath9k_hw_wait(ah,
+ AR_RTC_STATUS,
+ AR_RTC_STATUS_M,
+ AR_RTC_STATUS_ON)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: RTC not waking up\n",
+ __func__);
+ return false;
+ }
+
+ ath9k_hw_read_revisions(ah);
+
+ return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM);
+}
+
+static bool ath9k_hw_set_reset_reg(struct ath_hal *ah,
+ u32 type)
+{
+ REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);
+
+ switch (type) {
+ case ATH9K_RESET_POWER_ON:
+ return ath9k_hw_set_reset_power_on(ah);
+ break;
+ case ATH9K_RESET_WARM:
+ case ATH9K_RESET_COLD:
+ return ath9k_hw_set_reset(ah, type);
+ break;
+ default:
+ return false;
+ }
+}
+
+static inline
+struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "%s: invalid channel %u/0x%x; not marked as "
+ "2GHz or 5GHz\n", __func__, chan->channel,
+ chan->channelFlags);
+ return NULL;
+ }
+
+ if (!IS_CHAN_OFDM(chan) &&
+ !IS_CHAN_CCK(chan) &&
+ !IS_CHAN_HT20(chan) &&
+ !IS_CHAN_HT40(chan)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "%s: invalid channel %u/0x%x; not marked as "
+ "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n",
+ __func__, chan->channel, chan->channelFlags);
+ return NULL;
+ }
+
+ return ath9k_regd_check_channel(ah, chan);
+}
+
+static inline bool
+ath9k_hw_get_lower_upper_index(u8 target,
+ u8 *pList,
+ u16 listSize,
+ u16 *indexL,
+ u16 *indexR)
+{
+ u16 i;
+
+ if (target <= pList[0]) {
+ *indexL = *indexR = 0;
+ return true;
+ }
+ if (target >= pList[listSize - 1]) {
+ *indexL = *indexR = (u16) (listSize - 1);
+ return true;
+ }
+
+ for (i = 0; i < listSize - 1; i++) {
+ if (pList[i] == target) {
+ *indexL = *indexR = i;
+ return true;
+ }
+ if (target < pList[i + 1]) {
+ *indexL = i;
+ *indexR = (u16) (i + 1);
+ return false;
+ }
+ }
+ return false;
+}
+
+static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
+{
+ int16_t nfval;
+ int16_t sort[ATH9K_NF_CAL_HIST_MAX];
+ int i, j;
+
+ for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
+ sort[i] = nfCalBuffer[i];
+
+ for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
+ for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
+ if (sort[j] > sort[j - 1]) {
+ nfval = sort[j];
+ sort[j] = sort[j - 1];
+ sort[j - 1] = nfval;
+ }
+ }
+ }
+ nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
+
+ return nfval;
+}
+
+static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
+ int16_t *nfarray)
+{
+ int i;
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
+
+ if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
+ h[i].currIndex = 0;
+
+ if (h[i].invalidNFcount > 0) {
+ if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE
+ || nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
+ h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
+ } else {
+ h[i].invalidNFcount--;
+ h[i].privNF = nfarray[i];
+ }
+ } else {
+ h[i].privNF =
+ ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
+ }
+ }
+ return;
+}
+
+static void ar5416GetNoiseFloor(struct ath_hal *ah,
+ int16_t nfarray[NUM_NF_READINGS])
+{
+ int16_t nf;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
+ else
+ nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
+
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "NF calibrated [ctl] [chain 0] is %d\n", nf);
+ nfarray[0] = nf;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
+ AR9280_PHY_CH1_MINCCA_PWR);
+ else
+ nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
+ AR_PHY_CH1_MINCCA_PWR);
+
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+ "NF calibrated [ctl] [chain 1] is %d\n", nf);
+ nfarray[1] = nf;
+
+ if (!AR_SREV_9280(ah)) {
+ nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
+ AR_PHY_CH2_MINCCA_PWR);
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+ "NF calibrated [ctl] [chain 2] is %d\n", nf);
+ nfarray[2] = nf;
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
+ AR9280_PHY_EXT_MINCCA_PWR);
+ else
+ nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
+ AR_PHY_EXT_MINCCA_PWR);
+
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+ "NF calibrated [ext] [chain 0] is %d\n", nf);
+ nfarray[3] = nf;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
+ AR9280_PHY_CH1_EXT_MINCCA_PWR);
+ else
+ nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
+ AR_PHY_CH1_EXT_MINCCA_PWR);
+
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "NF calibrated [ext] [chain 1] is %d\n", nf);
+ nfarray[4] = nf;
+
+ if (!AR_SREV_9280(ah)) {
+ nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
+ AR_PHY_CH2_EXT_MINCCA_PWR);
+ if (nf & 0x100)
+ nf = 0 - ((nf ^ 0x1ff) + 1);
+ DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+ "NF calibrated [ext] [chain 2] is %d\n", nf);
+ nfarray[5] = nf;
+ }
+}
+
+static bool
+getNoiseFloorThresh(struct ath_hal *ah,
+ const struct ath9k_channel *chan,
+ int16_t *nft)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ switch (chan->chanmode) {
+ case CHANNEL_A:
+ case CHANNEL_A_HT20:
+ case CHANNEL_A_HT40PLUS:
+ case CHANNEL_A_HT40MINUS:
+ *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_5);
+ break;
+ case CHANNEL_B:
+ case CHANNEL_G:
+ case CHANNEL_G_HT20:
+ case CHANNEL_G_HT40PLUS:
+ case CHANNEL_G_HT40MINUS:
+ *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_2);
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "%s: invalid channel flags 0x%x\n", __func__,
+ chan->channelFlags);
+ return false;
+ }
+ return true;
+}
+
+static void ath9k_hw_start_nfcal(struct ath_hal *ah)
+{
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_ENABLE_NF);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+}
+
+static void
+ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+ struct ath9k_nfcal_hist *h;
+ int i, j;
+ int32_t val;
+ const u32 ar5416_cca_regs[6] = {
+ AR_PHY_CCA,
+ AR_PHY_CH1_CCA,
+ AR_PHY_CH2_CCA,
+ AR_PHY_EXT_CCA,
+ AR_PHY_CH1_EXT_CCA,
+ AR_PHY_CH2_EXT_CCA
+ };
+ u8 chainmask;
+
+ if (AR_SREV_9280(ah))
+ chainmask = 0x1B;
+ else
+ chainmask = 0x3F;
+
+#ifdef ATH_NF_PER_CHAN
+ h = chan->nfCalHist;
+#else
+ h = ah->nfCalHist;
+#endif
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (chainmask & (1 << i)) {
+ val = REG_READ(ah, ar5416_cca_regs[i]);
+ val &= 0xFFFFFE00;
+ val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+ REG_WRITE(ah, ar5416_cca_regs[i], val);
+ }
+ }
+
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_ENABLE_NF);
+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+ AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+
+ for (j = 0; j < 1000; j++) {
+ if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
+ AR_PHY_AGC_CONTROL_NF) == 0)
+ break;
+ udelay(10);
+ }
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (chainmask & (1 << i)) {
+ val = REG_READ(ah, ar5416_cca_regs[i]);
+ val &= 0xFFFFFE00;
+ val |= (((u32) (-50) << 1) & 0x1ff);
+ REG_WRITE(ah, ar5416_cca_regs[i], val);
+ }
+ }
+}
+
+static int16_t ath9k_hw_getnf(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ int16_t nf, nfThresh;
+ int16_t nfarray[NUM_NF_READINGS] = { 0 };
+ struct ath9k_nfcal_hist *h;
+ u8 chainmask;
+
+ if (AR_SREV_9280(ah))
+ chainmask = 0x1B;
+ else
+ chainmask = 0x3F;
+
+ chan->channelFlags &= (~CHANNEL_CW_INT);
+ if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: NF did not complete in calibration window\n",
+ __func__);
+ nf = 0;
+ chan->rawNoiseFloor = nf;
+ return chan->rawNoiseFloor;
+ } else {
+ ar5416GetNoiseFloor(ah, nfarray);
+ nf = nfarray[0];
+ if (getNoiseFloorThresh(ah, chan, &nfThresh)
+ && nf > nfThresh) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: noise floor failed detected; "
+ "detected %d, threshold %d\n", __func__,
+ nf, nfThresh);
+ chan->channelFlags |= CHANNEL_CW_INT;
+ }
+ }
+
+#ifdef ATH_NF_PER_CHAN
+ h = chan->nfCalHist;
+#else
+ h = ah->nfCalHist;
+#endif
+
+ ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
+ chan->rawNoiseFloor = h[0].privNF;
+
+ return chan->rawNoiseFloor;
+}
+
+static void ath9k_hw_update_mibstats(struct ath_hal *ah,
+ struct ath9k_mib_stats *stats)
+{
+ stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
+ stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
+ stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
+ stats->rts_good += REG_READ(ah, AR_RTS_OK);
+ stats->beacons += REG_READ(ah, AR_BEACON_CNT);
+}
+
+static void ath9k_enable_mib_counters(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable mib counters\n");
+
+ ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+ REG_WRITE(ah, AR_FILT_OFDM, 0);
+ REG_WRITE(ah, AR_FILT_CCK, 0);
+ REG_WRITE(ah, AR_MIBC,
+ ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
+ & 0x0f);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+}
+
+static void ath9k_hw_disable_mib_counters(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling MIB counters\n");
+
+ REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
+
+ ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+ REG_WRITE(ah, AR_FILT_OFDM, 0);
+ REG_WRITE(ah, AR_FILT_CCK, 0);
+}
+
+static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
+ if (ahp->ah_ani[i].c.channel == chan->channel)
+ return i;
+ if (ahp->ah_ani[i].c.channel == 0) {
+ ahp->ah_ani[i].c.channel = chan->channel;
+ ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
+ return i;
+ }
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "No more channel states left. Using channel 0\n");
+ return 0;
+}
+
+static void ath9k_hw_ani_attach(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ ahp->ah_hasHwPhyCounters = 1;
+
+ memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani));
+ for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
+ ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
+ ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
+ ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
+ ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
+ ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
+ ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
+ ahp->ah_ani[i].ofdmWeakSigDetectOff =
+ !ATH9K_ANI_USE_OFDM_WEAK_SIG;
+ ahp->ah_ani[i].cckWeakSigThreshold =
+ ATH9K_ANI_CCK_WEAK_SIG_THR;
+ ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
+ ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
+ if (ahp->ah_hasHwPhyCounters) {
+ ahp->ah_ani[i].ofdmPhyErrBase =
+ AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
+ ahp->ah_ani[i].cckPhyErrBase =
+ AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
+ }
+ }
+ if (ahp->ah_hasHwPhyCounters) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "Setting OfdmErrBase = 0x%08x\n",
+ ahp->ah_ani[0].ofdmPhyErrBase);
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
+ ahp->ah_ani[0].cckPhyErrBase);
+
+ REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
+ ath9k_enable_mib_counters(ah);
+ }
+ ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
+ if (ah->ah_config.enable_ani)
+ ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
+}
+
+static inline void ath9k_hw_ani_setup(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
+ const int coarseHigh[] = { -14, -14, -14, -14, -12 };
+ const int coarseLow[] = { -64, -64, -64, -64, -70 };
+ const int firpwr[] = { -78, -78, -78, -78, -80 };
+
+ for (i = 0; i < 5; i++) {
+ ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
+ ahp->ah_coarseHigh[i] = coarseHigh[i];
+ ahp->ah_coarseLow[i] = coarseLow[i];
+ ahp->ah_firpwr[i] = firpwr[i];
+ }
+}
+
+static void ath9k_hw_ani_detach(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detaching Ani\n");
+ if (ahp->ah_hasHwPhyCounters) {
+ ath9k_hw_disable_mib_counters(ah);
+ REG_WRITE(ah, AR_PHY_ERR_1, 0);
+ REG_WRITE(ah, AR_PHY_ERR_2, 0);
+ }
+}
+
+
+static bool ath9k_hw_ani_control(struct ath_hal *ah,
+ enum ath9k_ani_cmd cmd, int param)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState = ahp->ah_curani;
+
+ switch (cmd & ahp->ah_ani_function) {
+ case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
+ u32 level = param;
+
+ if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "%s: level out of range (%u > %u)\n",
+ __func__, level,
+ (unsigned) ARRAY_SIZE(ahp->
+ ah_totalSizeDesired));
+ return false;
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+ AR_PHY_DESIRED_SZ_TOT_DES,
+ ahp->ah_totalSizeDesired[level]);
+ REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+ AR_PHY_AGC_CTL1_COARSE_LOW,
+ ahp->ah_coarseLow[level]);
+ REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+ AR_PHY_AGC_CTL1_COARSE_HIGH,
+ ahp->ah_coarseHigh[level]);
+ REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+ AR_PHY_FIND_SIG_FIRPWR,
+ ahp->ah_firpwr[level]);
+
+ if (level > aniState->noiseImmunityLevel)
+ ahp->ah_stats.ast_ani_niup++;
+ else if (level < aniState->noiseImmunityLevel)
+ ahp->ah_stats.ast_ani_nidown++;
+ aniState->noiseImmunityLevel = level;
+ break;
+ }
+ case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+ const int m1ThreshLow[] = { 127, 50 };
+ const int m2ThreshLow[] = { 127, 40 };
+ const int m1Thresh[] = { 127, 0x4d };
+ const int m2Thresh[] = { 127, 0x40 };
+ const int m2CountThr[] = { 31, 16 };
+ const int m2CountThrLow[] = { 63, 48 };
+ u32 on = param ? 1 : 0;
+
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+ m1ThreshLow[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+ m2ThreshLow[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+ AR_PHY_SFCORR_M1_THRESH,
+ m1Thresh[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+ AR_PHY_SFCORR_M2_THRESH,
+ m2Thresh[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+ AR_PHY_SFCORR_M2COUNT_THR,
+ m2CountThr[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+ m2CountThrLow[on]);
+
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
+ m1ThreshLow[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
+ m2ThreshLow[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M1_THRESH,
+ m1Thresh[on]);
+ REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+ AR_PHY_SFCORR_EXT_M2_THRESH,
+ m2Thresh[on]);
+
+ if (on)
+ REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+ else
+ REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
+ AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+
+ if (!on != aniState->ofdmWeakSigDetectOff) {
+ if (on)
+ ahp->ah_stats.ast_ani_ofdmon++;
+ else
+ ahp->ah_stats.ast_ani_ofdmoff++;
+ aniState->ofdmWeakSigDetectOff = !on;
+ }
+ break;
+ }
+ case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
+ const int weakSigThrCck[] = { 8, 6 };
+ u32 high = param ? 1 : 0;
+
+ REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
+ AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
+ weakSigThrCck[high]);
+ if (high != aniState->cckWeakSigThreshold) {
+ if (high)
+ ahp->ah_stats.ast_ani_cckhigh++;
+ else
+ ahp->ah_stats.ast_ani_ccklow++;
+ aniState->cckWeakSigThreshold = high;
+ }
+ break;
+ }
+ case ATH9K_ANI_FIRSTEP_LEVEL:{
+ const int firstep[] = { 0, 4, 8 };
+ u32 level = param;
+
+ if (level >= ARRAY_SIZE(firstep)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "%s: level out of range (%u > %u)\n",
+ __func__, level,
+ (unsigned) ARRAY_SIZE(firstep));
+ return false;
+ }
+ REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+ AR_PHY_FIND_SIG_FIRSTEP,
+ firstep[level]);
+ if (level > aniState->firstepLevel)
+ ahp->ah_stats.ast_ani_stepup++;
+ else if (level < aniState->firstepLevel)
+ ahp->ah_stats.ast_ani_stepdown++;
+ aniState->firstepLevel = level;
+ break;
+ }
+ case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+ const int cycpwrThr1[] =
+ { 2, 4, 6, 8, 10, 12, 14, 16 };
+ u32 level = param;
+
+ if (level >= ARRAY_SIZE(cycpwrThr1)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "%s: level out of range (%u > %u)\n",
+ __func__, level,
+ (unsigned)
+ ARRAY_SIZE(cycpwrThr1));
+ return false;
+ }
+ REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+ AR_PHY_TIMING5_CYCPWR_THR1,
+ cycpwrThr1[level]);
+ if (level > aniState->spurImmunityLevel)
+ ahp->ah_stats.ast_ani_spurup++;
+ else if (level < aniState->spurImmunityLevel)
+ ahp->ah_stats.ast_ani_spurdown++;
+ aniState->spurImmunityLevel = level;
+ break;
+ }
+ case ATH9K_ANI_PRESENT:
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "%s: invalid cmd %u\n", __func__, cmd);
+ return false;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__);
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
+ "ofdmWeakSigDetectOff=%d\n",
+ aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
+ !aniState->ofdmWeakSigDetectOff);
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "cckWeakSigThreshold=%d, "
+ "firstepLevel=%d, listenTime=%d\n",
+ aniState->cckWeakSigThreshold, aniState->firstepLevel,
+ aniState->listenTime);
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
+ aniState->cycleCount, aniState->ofdmPhyErrCount,
+ aniState->cckPhyErrCount);
+ return true;
+}
+
+static void ath9k_ani_restart(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState;
+
+ if (!DO_ANI(ah))
+ return;
+
+ aniState = ahp->ah_curani;
+
+ aniState->listenTime = 0;
+ if (ahp->ah_hasHwPhyCounters) {
+ if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
+ aniState->ofdmPhyErrBase = 0;
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "OFDM Trigger is too high for hw counters\n");
+ } else {
+ aniState->ofdmPhyErrBase =
+ AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
+ }
+ if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
+ aniState->cckPhyErrBase = 0;
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "CCK Trigger is too high for hw counters\n");
+ } else {
+ aniState->cckPhyErrBase =
+ AR_PHY_COUNTMAX - aniState->cckTrigHigh;
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "%s: Writing ofdmbase=%u cckbase=%u\n",
+ __func__, aniState->ofdmPhyErrBase,
+ aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+ ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+ }
+ aniState->ofdmPhyErrCount = 0;
+ aniState->cckPhyErrCount = 0;
+}
+
+static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *chan = ah->ah_curchan;
+ struct ar5416AniState *aniState;
+ enum wireless_mode mode;
+ int32_t rssi;
+
+ if (!DO_ANI(ah))
+ return;
+
+ aniState = ahp->ah_curani;
+
+ if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
+ if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+ aniState->noiseImmunityLevel + 1)) {
+ return;
+ }
+ }
+
+ if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
+ if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+ aniState->spurImmunityLevel + 1)) {
+ return;
+ }
+ }
+
+ if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+ if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+ ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel + 1);
+ }
+ return;
+ }
+ rssi = BEACON_RSSI(ahp);
+ if (rssi > aniState->rssiThrHigh) {
+ if (!aniState->ofdmWeakSigDetectOff) {
+ if (ath9k_hw_ani_control(ah,
+ ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ false)) {
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+ 0);
+ return;
+ }
+ }
+ if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+ ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel + 1);
+ return;
+ }
+ } else if (rssi > aniState->rssiThrLow) {
+ if (aniState->ofdmWeakSigDetectOff)
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ true);
+ if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
+ ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel + 1);
+ return;
+ } else {
+ mode = ath9k_hw_chan2wmode(ah, chan);
+ if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
+ if (!aniState->ofdmWeakSigDetectOff)
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ false);
+ if (aniState->firstepLevel > 0)
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_FIRSTEP_LEVEL,
+ 0);
+ return;
+ }
+ }
+}
+
+static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *chan = ah->ah_curchan;
+ struct ar5416AniState *aniState;
+ enum wireless_mode mode;
+ int32_t rssi;
+
+ if (!DO_ANI(ah))
+ return;
+
+ aniState = ahp->ah_curani;
+ if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
+ if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+ aniState->noiseImmunityLevel + 1)) {
+ return;
+ }
+ }
+ if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+ if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
+ ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel + 1);
+ }
+ return;
+ }
+ rssi = BEACON_RSSI(ahp);
+ if (rssi > aniState->rssiThrLow) {
+ if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
+ ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel + 1);
+ } else {
+ mode = ath9k_hw_chan2wmode(ah, chan);
+ if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
+ if (aniState->firstepLevel > 0)
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_FIRSTEP_LEVEL,
+ 0);
+ }
+ }
+}
+
+static void ath9k_ani_reset(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState;
+ struct ath9k_channel *chan = ah->ah_curchan;
+ int index;
+
+ if (!DO_ANI(ah))
+ return;
+
+ index = ath9k_hw_get_ani_channel_idx(ah, chan);
+ aniState = &ahp->ah_ani[index];
+ ahp->ah_curani = aniState;
+
+ if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA
+ && ah->ah_opmode != ATH9K_M_IBSS) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "%s: Reset ANI state opmode %u\n", __func__,
+ ah->ah_opmode);
+ ahp->ah_stats.ast_ani_reset++;
+ ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
+ ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
+ ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ !ATH9K_ANI_USE_OFDM_WEAK_SIG);
+ ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
+ ATH9K_ANI_CCK_WEAK_SIG_THR);
+ ath9k_hw_setrxfilter(ah,
+ ath9k_hw_getrxfilter(ah) |
+ ATH9K_RX_FILTER_PHYERR);
+ if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+ ahp->ah_curani->ofdmTrigHigh =
+ ah->ah_config.ofdm_trig_high;
+ ahp->ah_curani->ofdmTrigLow =
+ ah->ah_config.ofdm_trig_low;
+ ahp->ah_curani->cckTrigHigh =
+ ah->ah_config.cck_trig_high;
+ ahp->ah_curani->cckTrigLow =
+ ah->ah_config.cck_trig_low;
+ }
+ ath9k_ani_restart(ah);
+ return;
+ }
+
+ if (aniState->noiseImmunityLevel != 0)
+ ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+ aniState->noiseImmunityLevel);
+ if (aniState->spurImmunityLevel != 0)
+ ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+ aniState->spurImmunityLevel);
+ if (aniState->ofdmWeakSigDetectOff)
+ ath9k_hw_ani_control(ah,
+ ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ !aniState->ofdmWeakSigDetectOff);
+ if (aniState->cckWeakSigThreshold)
+ ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
+ aniState->cckWeakSigThreshold);
+ if (aniState->firstepLevel != 0)
+ ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel);
+ if (ahp->ah_hasHwPhyCounters) {
+ ath9k_hw_setrxfilter(ah,
+ ath9k_hw_getrxfilter(ah) &
+ ~ATH9K_RX_FILTER_PHYERR);
+ ath9k_ani_restart(ah);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+ } else {
+ ath9k_ani_restart(ah);
+ ath9k_hw_setrxfilter(ah,
+ ath9k_hw_getrxfilter(ah) |
+ ATH9K_RX_FILTER_PHYERR);
+ }
+}
+
+void ath9k_hw_procmibevent(struct ath_hal *ah,
+ const struct ath9k_node_stats *stats)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 phyCnt1, phyCnt2;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n");
+
+ REG_WRITE(ah, AR_FILT_OFDM, 0);
+ REG_WRITE(ah, AR_FILT_CCK, 0);
+ if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
+ REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
+
+ ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+ ahp->ah_stats.ast_nodestats = *stats;
+
+ if (!DO_ANI(ah))
+ return;
+
+ phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+ phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+ if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
+ ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
+ struct ar5416AniState *aniState = ahp->ah_curani;
+ u32 ofdmPhyErrCnt, cckPhyErrCnt;
+
+ ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+ ahp->ah_stats.ast_ani_ofdmerrs +=
+ ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+ aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+ cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+ ahp->ah_stats.ast_ani_cckerrs +=
+ cckPhyErrCnt - aniState->cckPhyErrCount;
+ aniState->cckPhyErrCount = cckPhyErrCnt;
+
+ if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
+ ath9k_hw_ani_ofdm_err_trigger(ah);
+ if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
+ ath9k_hw_ani_cck_err_trigger(ah);
+
+ ath9k_ani_restart(ah);
+ }
+}
+
+static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState;
+ int32_t rssi;
+
+ aniState = ahp->ah_curani;
+
+ if (ah->ah_opmode == ATH9K_M_HOSTAP) {
+ if (aniState->firstepLevel > 0) {
+ if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel - 1)) {
+ return;
+ }
+ }
+ } else {
+ rssi = BEACON_RSSI(ahp);
+ if (rssi > aniState->rssiThrHigh) {
+ /* XXX: Handle me */
+ } else if (rssi > aniState->rssiThrLow) {
+ if (aniState->ofdmWeakSigDetectOff) {
+ if (ath9k_hw_ani_control(ah,
+ ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
+ true) ==
+ true) {
+ return;
+ }
+ }
+ if (aniState->firstepLevel > 0) {
+ if (ath9k_hw_ani_control
+ (ah, ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel - 1) ==
+ true) {
+ return;
+ }
+ }
+ } else {
+ if (aniState->firstepLevel > 0) {
+ if (ath9k_hw_ani_control
+ (ah, ATH9K_ANI_FIRSTEP_LEVEL,
+ aniState->firstepLevel - 1) ==
+ true) {
+ return;
+ }
+ }
+ }
+ }
+
+ if (aniState->spurImmunityLevel > 0) {
+ if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
+ aniState->spurImmunityLevel - 1)) {
+ return;
+ }
+ }
+
+ if (aniState->noiseImmunityLevel > 0) {
+ ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
+ aniState->noiseImmunityLevel - 1);
+ return;
+ }
+}
+
+static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState;
+ u32 txFrameCount, rxFrameCount, cycleCount;
+ int32_t listenTime;
+
+ txFrameCount = REG_READ(ah, AR_TFCNT);
+ rxFrameCount = REG_READ(ah, AR_RFCNT);
+ cycleCount = REG_READ(ah, AR_CCCNT);
+
+ aniState = ahp->ah_curani;
+ if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
+
+ listenTime = 0;
+ ahp->ah_stats.ast_ani_lzero++;
+ } else {
+ int32_t ccdelta = cycleCount - aniState->cycleCount;
+ int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
+ int32_t tfdelta = txFrameCount - aniState->txFrameCount;
+ listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
+ }
+ aniState->cycleCount = cycleCount;
+ aniState->txFrameCount = txFrameCount;
+ aniState->rxFrameCount = rxFrameCount;
+
+ return listenTime;
+}
+
+void ath9k_hw_ani_monitor(struct ath_hal *ah,
+ const struct ath9k_node_stats *stats,
+ struct ath9k_channel *chan)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416AniState *aniState;
+ int32_t listenTime;
+
+ aniState = ahp->ah_curani;
+ ahp->ah_stats.ast_nodestats = *stats;
+
+ listenTime = ath9k_hw_ani_get_listen_time(ah);
+ if (listenTime < 0) {
+ ahp->ah_stats.ast_ani_lneg++;
+ ath9k_ani_restart(ah);
+ return;
+ }
+
+ aniState->listenTime += listenTime;
+
+ if (ahp->ah_hasHwPhyCounters) {
+ u32 phyCnt1, phyCnt2;
+ u32 ofdmPhyErrCnt, cckPhyErrCnt;
+
+ ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
+
+ phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
+ phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
+
+ if (phyCnt1 < aniState->ofdmPhyErrBase ||
+ phyCnt2 < aniState->cckPhyErrBase) {
+ if (phyCnt1 < aniState->ofdmPhyErrBase) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "%s: phyCnt1 0x%x, resetting "
+ "counter value to 0x%x\n",
+ __func__, phyCnt1,
+ aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_1,
+ aniState->ofdmPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_1,
+ AR_PHY_ERR_OFDM_TIMING);
+ }
+ if (phyCnt2 < aniState->cckPhyErrBase) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANI,
+ "%s: phyCnt2 0x%x, resetting "
+ "counter value to 0x%x\n",
+ __func__, phyCnt2,
+ aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_2,
+ aniState->cckPhyErrBase);
+ REG_WRITE(ah, AR_PHY_ERR_MASK_2,
+ AR_PHY_ERR_CCK_TIMING);
+ }
+ return;
+ }
+
+ ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
+ ahp->ah_stats.ast_ani_ofdmerrs +=
+ ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
+ aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
+
+ cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
+ ahp->ah_stats.ast_ani_cckerrs +=
+ cckPhyErrCnt - aniState->cckPhyErrCount;
+ aniState->cckPhyErrCount = cckPhyErrCnt;
+ }
+
+ if (!DO_ANI(ah))
+ return;
+
+ if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
+ if (aniState->ofdmPhyErrCount <= aniState->listenTime *
+ aniState->ofdmTrigLow / 1000 &&
+ aniState->cckPhyErrCount <= aniState->listenTime *
+ aniState->cckTrigLow / 1000)
+ ath9k_hw_ani_lower_immunity(ah);
+ ath9k_ani_restart(ah);
+ } else if (aniState->listenTime > ahp->ah_aniPeriod) {
+ if (aniState->ofdmPhyErrCount > aniState->listenTime *
+ aniState->ofdmTrigHigh / 1000) {
+ ath9k_hw_ani_ofdm_err_trigger(ah);
+ ath9k_ani_restart(ah);
+ } else if (aniState->cckPhyErrCount >
+ aniState->listenTime * aniState->cckTrigHigh /
+ 1000) {
+ ath9k_hw_ani_cck_err_trigger(ah);
+ ath9k_ani_restart(ah);
+ }
+ }
+}
+
+#ifndef ATH_NF_PER_CHAN
+static void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah)
+{
+ int i, j;
+
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ ah->nfCalHist[i].currIndex = 0;
+ ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].invalidNFcount =
+ AR_PHY_CCA_FILTERWINDOW_LENGTH;
+ for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
+ ah->nfCalHist[i].nfCalBuffer[j] =
+ AR_PHY_CCA_MAX_GOOD_VALUE;
+ }
+ }
+ return;
+}
+#endif
+
+static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah,
+ u32 gpio, u32 type)
+{
+ int addr;
+ u32 gpio_shift, tmp;
+
+ if (gpio > 11)
+ addr = AR_GPIO_OUTPUT_MUX3;
+ else if (gpio > 5)
+ addr = AR_GPIO_OUTPUT_MUX2;
+ else
+ addr = AR_GPIO_OUTPUT_MUX1;
+
+ gpio_shift = (gpio % 6) * 5;
+
+ if (AR_SREV_9280_20_OR_LATER(ah)
+ || (addr != AR_GPIO_OUTPUT_MUX1)) {
+ REG_RMW(ah, addr, (type << gpio_shift),
+ (0x1f << gpio_shift));
+ } else {
+ tmp = REG_READ(ah, addr);
+ tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0);
+ tmp &= ~(0x1f << gpio_shift);
+ tmp |= (type << gpio_shift);
+ REG_WRITE(ah, addr, tmp);
+ }
+}
+
+static bool ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
+ enum ath9k_gpio_output_mux_type
+ halSignalType)
+{
+ u32 ah_signal_type;
+ u32 gpio_shift;
+
+ static u32 MuxSignalConversionTable[] = {
+
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT,
+
+ AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED,
+
+ AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED,
+
+ AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED,
+
+ AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED,
+ };
+
+ if ((halSignalType >= 0)
+ && (halSignalType < ARRAY_SIZE(MuxSignalConversionTable)))
+ ah_signal_type = MuxSignalConversionTable[halSignalType];
+ else
+ return false;
+
+ ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);
+
+ gpio_shift = 2 * gpio;
+
+ REG_RMW(ah,
+ AR_GPIO_OE_OUT,
+ (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),
+ (AR_GPIO_OE_OUT_DRV << gpio_shift));
+
+ return true;
+}
+
+static bool ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio,
+ u32 val)
+{
+ REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
+ AR_GPIO_BIT(gpio));
+ return true;
+}
+
+static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
+{
+ if (gpio >= ah->ah_caps.num_gpio_pins)
+ return 0xffffffff;
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ return (MS
+ (REG_READ(ah, AR_GPIO_IN_OUT),
+ AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0;
+ } else {
+ return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) &
+ AR_GPIO_BIT(gpio)) != 0;
+ }
+}
+
+static inline int ath9k_hw_post_attach(struct ath_hal *ah)
+{
+ int ecode;
+
+ if (!ath9k_hw_chip_test(ah)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "%s: hardware self-test failed\n", __func__);
+ return -ENODEV;
+ }
+
+ ecode = ath9k_hw_rf_claim(ah);
+ if (ecode != 0)
+ return ecode;
+
+ ecode = ath9k_hw_eeprom_attach(ah);
+ if (ecode != 0)
+ return ecode;
+ ecode = ath9k_hw_rfattach(ah);
+ if (ecode != 0)
+ return ecode;
+
+ if (!AR_SREV_9100(ah)) {
+ ath9k_hw_ani_setup(ah);
+ ath9k_hw_ani_attach(ah);
+ }
+ return 0;
+}
+
+static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
+ struct ar5416_eeprom *pEepData,
+ u32 reg, u32 value)
+{
+ struct base_eep_header *pBase = &(pEepData->baseEepHeader);
+
+ switch (ah->ah_devid) {
+ case AR9280_DEVID_PCI:
+ if (reg == 0x7894) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ "ini VAL: %x EEPROM: %x\n", value,
+ (pBase->version & 0xff));
+
+ if ((pBase->version & 0xff) > 0x0a) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ "PWDCLKIND: %d\n",
+ pBase->pwdclkind);
+ value &= ~AR_AN_TOP2_PWDCLKIND;
+ value |= AR_AN_TOP2_PWDCLKIND & (pBase->
+ pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
+ } else {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ "PWDCLKIND Earlier Rev\n");
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ "final ini VAL: %x\n", value);
+ }
+ break;
+ }
+ return value;
+}
+
+static bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ u16 capField = 0, eeval;
+
+ eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_0);
+
+ ah->ah_currentRD = eeval;
+
+ eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_1);
+ ah->ah_currentRDExt = eeval;
+
+ capField = ath9k_hw_get_eeprom(ahp, EEP_OP_CAP);
+
+ if (ah->ah_opmode != ATH9K_M_HOSTAP &&
+ ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) {
+ if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65)
+ ah->ah_currentRD += 5;
+ else if (ah->ah_currentRD == 0x41)
+ ah->ah_currentRD = 0x43;
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: regdomain mapped to 0x%x\n", __func__,
+ ah->ah_currentRD);
+ }
+
+ eeval = ath9k_hw_get_eeprom(ahp, EEP_OP_MODE);
+ bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX);
+
+ if (eeval & AR5416_OPFLAGS_11A) {
+ set_bit(ATH9K_MODE_11A, pCap->wireless_modes);
+ if (ah->ah_config.ht_enable) {
+ if (!(eeval & AR5416_OPFLAGS_N_5G_HT20))
+ set_bit(ATH9K_MODE_11NA_HT20,
+ pCap->wireless_modes);
+ if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) {
+ set_bit(ATH9K_MODE_11NA_HT40PLUS,
+ pCap->wireless_modes);
+ set_bit(ATH9K_MODE_11NA_HT40MINUS,
+ pCap->wireless_modes);
+ }
+ }
+ }
+
+ if (eeval & AR5416_OPFLAGS_11G) {
+ set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
+ set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
+ if (ah->ah_config.ht_enable) {
+ if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
+ set_bit(ATH9K_MODE_11NG_HT20,
+ pCap->wireless_modes);
+ if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) {
+ set_bit(ATH9K_MODE_11NG_HT40PLUS,
+ pCap->wireless_modes);
+ set_bit(ATH9K_MODE_11NG_HT40MINUS,
+ pCap->wireless_modes);
+ }
+ }
+ }
+
+ pCap->tx_chainmask = ath9k_hw_get_eeprom(ahp, EEP_TX_MASK);
+ if ((ah->ah_isPciExpress)
+ || (eeval & AR5416_OPFLAGS_11A)) {
+ pCap->rx_chainmask =
+ ath9k_hw_get_eeprom(ahp, EEP_RX_MASK);
+ } else {
+ pCap->rx_chainmask =
+ (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7;
+ }
+
+ if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0)))
+ ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA;
+
+ pCap->low_2ghz_chan = 2312;
+ pCap->high_2ghz_chan = 2732;
+
+ pCap->low_5ghz_chan = 4920;
+ pCap->high_5ghz_chan = 6100;
+
+ pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP;
+ pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP;
+ pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM;
+
+ pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP;
+ pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP;
+ pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM;
+
+ pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD;
+
+ if (ah->ah_config.ht_enable)
+ pCap->hw_caps |= ATH9K_HW_CAP_HT;
+ else
+ pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
+
+ pCap->hw_caps |= ATH9K_HW_CAP_GTT;
+ pCap->hw_caps |= ATH9K_HW_CAP_VEOL;
+ pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK;
+ pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH;
+
+ if (capField & AR_EEPROM_EEPCAP_MAXQCU)
+ pCap->total_queues =
+ MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
+ else
+ pCap->total_queues = ATH9K_NUM_TX_QUEUES;
+
+ if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES)
+ pCap->keycache_size =
+ 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES);
+ else
+ pCap->keycache_size = AR_KEYTABLE_SIZE;
+
+ pCap->hw_caps |= ATH9K_HW_CAP_FASTCC;
+ pCap->num_mr_retries = 4;
+ pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ pCap->num_gpio_pins = AR928X_NUM_GPIO;
+ else
+ pCap->num_gpio_pins = AR_NUM_GPIO;
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ pCap->hw_caps |= ATH9K_HW_CAP_WOW;
+ pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
+ } else {
+ pCap->hw_caps &= ~ATH9K_HW_CAP_WOW;
+ pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT;
+ }
+
+ if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) {
+ pCap->hw_caps |= ATH9K_HW_CAP_CST;
+ pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX;
+ } else {
+ pCap->rts_aggr_limit = (8 * 1024);
+ }
+
+ pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
+
+ ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT);
+ if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
+ ahp->ah_gpioSelect =
+ MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
+ ahp->ah_polarity =
+ MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
+
+ ath9k_hw_setcapability(ah, ATH9K_CAP_RFSILENT, 1, true,
+ NULL);
+ pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
+ }
+
+ if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
+ (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
+ (ah->ah_macVersion == AR_SREV_VERSION_9160) ||
+ (ah->ah_macVersion == AR_SREV_VERSION_9100) ||
+ (ah->ah_macVersion == AR_SREV_VERSION_9280))
+ pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
+ else
+ pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
+
+ if (AR_SREV_9280(ah))
+ pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
+ else
+ pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
+
+ if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) {
+ pCap->reg_cap =
+ AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
+ AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
+ AR_EEPROM_EEREGCAP_EN_KK_U2 |
+ AR_EEPROM_EEREGCAP_EN_KK_MIDBAND;
+ } else {
+ pCap->reg_cap =
+ AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
+ AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
+ }
+
+ pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
+
+ pCap->num_antcfg_5ghz =
+ ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_5GHZ);
+ pCap->num_antcfg_2ghz =
+ ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_2GHZ);
+
+ return true;
+}
+
+static void ar5416DisablePciePhy(struct ath_hal *ah)
+{
+ if (!AR_SREV_9100(ah))
+ return;
+
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
+
+ REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+}
+
+static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip)
+{
+ REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+ if (setChip) {
+ REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN);
+ if (!AR_SREV_9100(ah))
+ REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
+
+ REG_CLR_BIT(ah, (u16) (AR_RTC_RESET),
+ AR_RTC_RESET_EN);
+ }
+}
+
+static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip)
+{
+ REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+ if (setChip) {
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+ REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_ON_INT);
+ } else {
+ REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN);
+ }
+ }
+}
+
+static bool ath9k_hw_set_power_awake(struct ath_hal *ah,
+ int setChip)
+{
+ u32 val;
+ int i;
+
+ if (setChip) {
+ if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) ==
+ AR_RTC_STATUS_SHUTDOWN) {
+ if (ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)
+ != true) {
+ return false;
+ }
+ }
+ if (AR_SREV_9100(ah))
+ REG_SET_BIT(ah, AR_RTC_RESET,
+ AR_RTC_RESET_EN);
+
+ REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN);
+ udelay(50);
+
+ for (i = POWER_UP_TIME / 50; i > 0; i--) {
+ val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
+ if (val == AR_RTC_STATUS_ON)
+ break;
+ udelay(50);
+ REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
+ AR_RTC_FORCE_WAKE_EN);
+ }
+ if (i == 0) {
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ "%s: Failed to wakeup in %uus\n",
+ __func__, POWER_UP_TIME / 20);
+ return false;
+ }
+ }
+
+ REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+ return true;
+}
+
+bool ath9k_hw_setpower(struct ath_hal *ah,
+ enum ath9k_power_mode mode)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ static const char *modes[] = {
+ "AWAKE",
+ "FULL-SLEEP",
+ "NETWORK SLEEP",
+ "UNDEFINED"
+ };
+ int status = true, setChip = true;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__,
+ modes[ahp->ah_powerMode], modes[mode],
+ setChip ? "set chip " : "");
+
+ switch (mode) {
+ case ATH9K_PM_AWAKE:
+ status = ath9k_hw_set_power_awake(ah, setChip);
+ break;
+ case ATH9K_PM_FULL_SLEEP:
+ ath9k_set_power_sleep(ah, setChip);
+ ahp->ah_chipFullSleep = true;
+ break;
+ case ATH9K_PM_NETWORK_SLEEP:
+ ath9k_set_power_network_sleep(ah, setChip);
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ "%s: unknown power mode %u\n", __func__, mode);
+ return false;
+ }
+ ahp->ah_powerMode = mode;
+ return status;
+}
+
+static struct ath_hal *ath9k_hw_do_attach(u16 devid,
+ struct ath_softc *sc,
+ void __iomem *mem,
+ int *status)
+{
+ struct ath_hal_5416 *ahp;
+ struct ath_hal *ah;
+ int ecode;
+#ifndef CONFIG_SLOW_ANT_DIV
+ u32 i;
+ u32 j;
+#endif
+
+ ahp = ath9k_hw_newstate(devid, sc, mem, status);
+ if (ahp == NULL)
+ return NULL;
+
+ ah = &ahp->ah;
+
+ ath9k_hw_set_defaults(ah);
+
+ if (ah->ah_config.intr_mitigation != 0)
+ ahp->ah_intrMitigation = true;
+
+ if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't reset chip\n",
+ __func__);
+ ecode = -EIO;
+ goto bad;
+ }
+
+ if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't wakeup chip\n",
+ __func__);
+ ecode = -EIO;
+ goto bad;
+ }
+
+ if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) {
+ if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) {
+ ah->ah_config.serialize_regmode =
+ SER_REG_MODE_ON;
+ } else {
+ ah->ah_config.serialize_regmode =
+ SER_REG_MODE_OFF;
+ }
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "%s: serialize_regmode is %d\n",
+ __func__, ah->ah_config.serialize_regmode);
+
+ if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) &&
+ (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) &&
+ (ah->ah_macVersion != AR_SREV_VERSION_9160) &&
+ (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "%s: Mac Chip Rev 0x%02x.%x is not supported by "
+ "this driver\n", __func__,
+ ah->ah_macVersion, ah->ah_macRev);
+ ecode = -EOPNOTSUPP;
+ goto bad;
+ }
+
+ if (AR_SREV_9100(ah)) {
+ ahp->ah_iqCalData.calData = &iq_cal_multi_sample;
+ ahp->ah_suppCals = IQ_MISMATCH_CAL;
+ ah->ah_isPciExpress = false;
+ }
+ ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
+
+ if (AR_SREV_9160_10_OR_LATER(ah)) {
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ ahp->ah_iqCalData.calData = &iq_cal_single_sample;
+ ahp->ah_adcGainCalData.calData =
+ &adc_gain_cal_single_sample;
+ ahp->ah_adcDcCalData.calData =
+ &adc_dc_cal_single_sample;
+ ahp->ah_adcDcCalInitData.calData =
+ &adc_init_dc_cal;
+ } else {
+ ahp->ah_iqCalData.calData = &iq_cal_multi_sample;
+ ahp->ah_adcGainCalData.calData =
+ &adc_gain_cal_multi_sample;
+ ahp->ah_adcDcCalData.calData =
+ &adc_dc_cal_multi_sample;
+ ahp->ah_adcDcCalInitData.calData =
+ &adc_init_dc_cal;
+ }
+ ahp->ah_suppCals =
+ ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
+ }
+
+ if (AR_SREV_9160(ah)) {
+ ah->ah_config.enable_ani = 1;
+ ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
+ ATH9K_ANI_FIRSTEP_LEVEL);
+ } else {
+ ahp->ah_ani_function = ATH9K_ANI_ALL;
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ ahp->ah_ani_function &=
+ ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+ }
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__,
+ ah->ah_macVersion, ah->ah_macRev);
+
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2,
+ ARRAY_SIZE(ar9280Modes_9280_2), 6);
+ INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2,
+ ARRAY_SIZE(ar9280Common_9280_2), 2);
+
+ if (ah->ah_config.pcie_clock_req) {
+ INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+ ar9280PciePhy_clkreq_off_L1_9280,
+ ARRAY_SIZE
+ (ar9280PciePhy_clkreq_off_L1_9280),
+ 2);
+ } else {
+ INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+ ar9280PciePhy_clkreq_always_on_L1_9280,
+ ARRAY_SIZE
+ (ar9280PciePhy_clkreq_always_on_L1_9280),
+ 2);
+ }
+ INIT_INI_ARRAY(&ahp->ah_iniModesAdditional,
+ ar9280Modes_fast_clock_9280_2,
+ ARRAY_SIZE(ar9280Modes_fast_clock_9280_2),
+ 3);
+ } else if (AR_SREV_9280_10_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280,
+ ARRAY_SIZE(ar9280Modes_9280), 6);
+ INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280,
+ ARRAY_SIZE(ar9280Common_9280), 2);
+ } else if (AR_SREV_9160_10_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160,
+ ARRAY_SIZE(ar5416Modes_9160), 6);
+ INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160,
+ ARRAY_SIZE(ar5416Common_9160), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160,
+ ARRAY_SIZE(ar5416Bank0_9160), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160,
+ ARRAY_SIZE(ar5416BB_RfGain_9160), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160,
+ ARRAY_SIZE(ar5416Bank1_9160), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160,
+ ARRAY_SIZE(ar5416Bank2_9160), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160,
+ ARRAY_SIZE(ar5416Bank3_9160), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160,
+ ARRAY_SIZE(ar5416Bank6_9160), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160,
+ ARRAY_SIZE(ar5416Bank6TPC_9160), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160,
+ ARRAY_SIZE(ar5416Bank7_9160), 2);
+ if (AR_SREV_9160_11(ah)) {
+ INIT_INI_ARRAY(&ahp->ah_iniAddac,
+ ar5416Addac_91601_1,
+ ARRAY_SIZE(ar5416Addac_91601_1), 2);
+ } else {
+ INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160,
+ ARRAY_SIZE(ar5416Addac_9160), 2);
+ }
+ } else if (AR_SREV_9100_OR_LATER(ah)) {
+ INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100,
+ ARRAY_SIZE(ar5416Modes_9100), 6);
+ INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100,
+ ARRAY_SIZE(ar5416Common_9100), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100,
+ ARRAY_SIZE(ar5416Bank0_9100), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100,
+ ARRAY_SIZE(ar5416BB_RfGain_9100), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100,
+ ARRAY_SIZE(ar5416Bank1_9100), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100,
+ ARRAY_SIZE(ar5416Bank2_9100), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100,
+ ARRAY_SIZE(ar5416Bank3_9100), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100,
+ ARRAY_SIZE(ar5416Bank6_9100), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100,
+ ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100,
+ ARRAY_SIZE(ar5416Bank7_9100), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100,
+ ARRAY_SIZE(ar5416Addac_9100), 2);
+ } else {
+ INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes,
+ ARRAY_SIZE(ar5416Modes), 6);
+ INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common,
+ ARRAY_SIZE(ar5416Common), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0,
+ ARRAY_SIZE(ar5416Bank0), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain,
+ ARRAY_SIZE(ar5416BB_RfGain), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1,
+ ARRAY_SIZE(ar5416Bank1), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2,
+ ARRAY_SIZE(ar5416Bank2), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3,
+ ARRAY_SIZE(ar5416Bank3), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6,
+ ARRAY_SIZE(ar5416Bank6), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC,
+ ARRAY_SIZE(ar5416Bank6TPC), 3);
+ INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7,
+ ARRAY_SIZE(ar5416Bank7), 2);
+ INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac,
+ ARRAY_SIZE(ar5416Addac), 2);
+ }
+
+ if (ah->ah_isPciExpress)
+ ath9k_hw_configpcipowersave(ah, 0);
+ else
+ ar5416DisablePciePhy(ah);
+
+ ecode = ath9k_hw_post_attach(ah);
+ if (ecode != 0)
+ goto bad;
+
+#ifndef CONFIG_SLOW_ANT_DIV
+ if (ah->ah_devid == AR9280_DEVID_PCI) {
+ for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
+ u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
+
+ for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) {
+ u32 val = INI_RA(&ahp->ah_iniModes, i, j);
+
+ INI_RA(&ahp->ah_iniModes, i, j) =
+ ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom,
+ reg, val);
+ }
+ }
+ }
+#endif
+
+ if (!ath9k_hw_fill_cap_info(ah)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "%s:failed ath9k_hw_fill_cap_info\n", __func__);
+ ecode = -EINVAL;
+ goto bad;
+ }
+
+ ecode = ath9k_hw_init_macaddr(ah);
+ if (ecode != 0) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "%s: failed initializing mac address\n",
+ __func__);
+ goto bad;
+ }
+
+ if (AR_SREV_9285(ah))
+ ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S);
+ else
+ ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S);
+
+#ifndef ATH_NF_PER_CHAN
+
+ ath9k_init_nfcal_hist_buffer(ah);
+#endif
+
+ return ah;
+
+bad:
+ if (ahp)
+ ath9k_hw_detach((struct ath_hal *) ahp);
+ if (status)
+ *status = ecode;
+ return NULL;
+}
+
+void ath9k_hw_detach(struct ath_hal *ah)
+{
+ if (!AR_SREV_9100(ah))
+ ath9k_hw_ani_detach(ah);
+ ath9k_hw_rfdetach(ah);
+
+ ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+ kfree(ah);
+}
+
+bool ath9k_get_channel_edges(struct ath_hal *ah,
+ u16 flags, u16 *low,
+ u16 *high)
+{
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+ if (flags & CHANNEL_5GHZ) {
+ *low = pCap->low_5ghz_chan;
+ *high = pCap->high_5ghz_chan;
+ return true;
+ }
+ if ((flags & CHANNEL_2GHZ)) {
+ *low = pCap->low_2ghz_chan;
+ *high = pCap->high_2ghz_chan;
+
+ return true;
+ }
+ return false;
+}
+
+static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin,
+ u8 pwrMax,
+ u8 *pPwrList,
+ u8 *pVpdList,
+ u16
+ numIntercepts,
+ u8 *pRetVpdList)
+{
+ u16 i, k;
+ u8 currPwr = pwrMin;
+ u16 idxL = 0, idxR = 0;
+
+ for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
+ ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
+ numIntercepts, &(idxL),
+ &(idxR));
+ if (idxR < 1)
+ idxR = 1;
+ if (idxL == numIntercepts - 1)
+ idxL = (u16) (numIntercepts - 2);
+ if (pPwrList[idxL] == pPwrList[idxR])
+ k = pVpdList[idxL];
+ else
+ k = (u16) (((currPwr -
+ pPwrList[idxL]) *
+ pVpdList[idxR] +
+ (pPwrList[idxR] -
+ currPwr) * pVpdList[idxL]) /
+ (pPwrList[idxR] -
+ pPwrList[idxL]));
+ pRetVpdList[i] = (u8) k;
+ currPwr += 2;
+ }
+
+ return true;
+}
+
+static inline void
+ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ struct cal_data_per_freq *pRawDataSet,
+ u8 *bChans,
+ u16 availPiers,
+ u16 tPdGainOverlap,
+ int16_t *pMinCalPower,
+ u16 *pPdGainBoundaries,
+ u8 *pPDADCValues,
+ u16 numXpdGains)
+{
+ int i, j, k;
+ int16_t ss;
+ u16 idxL = 0, idxR = 0, numPiers;
+ static u8 vpdTableL[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableR[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ static u8 vpdTableI[AR5416_NUM_PD_GAINS]
+ [AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+
+ u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+ u8 minPwrT4[AR5416_NUM_PD_GAINS];
+ u8 maxPwrT4[AR5416_NUM_PD_GAINS];
+ int16_t vpdStep;
+ int16_t tmpVal;
+ u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+ bool match;
+ int16_t minDelta = 0;
+ struct chan_centers centers;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ for (numPiers = 0; numPiers < availPiers; numPiers++) {
+ if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
+ break;
+ }
+
+ match = ath9k_hw_get_lower_upper_index((u8)
+ FREQ2FBIN(centers.
+ synth_center,
+ IS_CHAN_2GHZ
+ (chan)), bChans,
+ numPiers, &idxL, &idxR);
+
+ if (match) {
+ for (i = 0; i < numXpdGains; i++) {
+ minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
+ maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pRawDataSet[idxL].
+ pwrPdg[i],
+ pRawDataSet[idxL].
+ vpdPdg[i],
+ AR5416_PD_GAIN_ICEPTS,
+ vpdTableI[i]);
+ }
+ } else {
+ for (i = 0; i < numXpdGains; i++) {
+ pVpdL = pRawDataSet[idxL].vpdPdg[i];
+ pPwrL = pRawDataSet[idxL].pwrPdg[i];
+ pVpdR = pRawDataSet[idxR].vpdPdg[i];
+ pPwrR = pRawDataSet[idxR].pwrPdg[i];
+
+ minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
+
+ maxPwrT4[i] =
+ min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1],
+ pPwrR[AR5416_PD_GAIN_ICEPTS - 1]);
+
+
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrL, pVpdL,
+ AR5416_PD_GAIN_ICEPTS,
+ vpdTableL[i]);
+ ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
+ pPwrR, pVpdR,
+ AR5416_PD_GAIN_ICEPTS,
+ vpdTableR[i]);
+
+ for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
+ vpdTableI[i][j] =
+ (u8) (ath9k_hw_interpolate
+ ((u16)
+ FREQ2FBIN(centers.
+ synth_center,
+ IS_CHAN_2GHZ
+ (chan)),
+ bChans[idxL],
+ bChans[idxR], vpdTableL[i]
+ [j], vpdTableR[i]
+ [j]));
+ }
+ }
+ }
+
+ *pMinCalPower = (int16_t) (minPwrT4[0] / 2);
+
+ k = 0;
+ for (i = 0; i < numXpdGains; i++) {
+ if (i == (numXpdGains - 1))
+ pPdGainBoundaries[i] =
+ (u16) (maxPwrT4[i] / 2);
+ else
+ pPdGainBoundaries[i] =
+ (u16) ((maxPwrT4[i] +
+ minPwrT4[i + 1]) / 4);
+
+ pPdGainBoundaries[i] =
+ min((u16) AR5416_MAX_RATE_POWER,
+ pPdGainBoundaries[i]);
+
+ if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
+ minDelta = pPdGainBoundaries[0] - 23;
+ pPdGainBoundaries[0] = 23;
+ } else {
+ minDelta = 0;
+ }
+
+ if (i == 0) {
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ss = (int16_t) (0 - (minPwrT4[i] / 2));
+ else
+ ss = 0;
+ } else {
+ ss = (int16_t) ((pPdGainBoundaries[i - 1] -
+ (minPwrT4[i] / 2)) -
+ tPdGainOverlap + 1 + minDelta);
+ }
+ vpdStep = (int16_t) (vpdTableI[i][1] - vpdTableI[i][0]);
+ vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep);
+
+ while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t) (vpdTableI[i][0] + ss * vpdStep);
+ pPDADCValues[k++] =
+ (u8) ((tmpVal < 0) ? 0 : tmpVal);
+ ss++;
+ }
+
+ sizeCurrVpdTable =
+ (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
+ tgtIndex = (u8) (pPdGainBoundaries[i] + tPdGainOverlap -
+ (minPwrT4[i] / 2));
+ maxIndex = (tgtIndex <
+ sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
+
+ while ((ss < maxIndex)
+ && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ pPDADCValues[k++] = vpdTableI[i][ss++];
+ }
+
+ vpdStep = (int16_t) (vpdTableI[i][sizeCurrVpdTable - 1] -
+ vpdTableI[i][sizeCurrVpdTable - 2]);
+ vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep);
+
+ if (tgtIndex > maxIndex) {
+ while ((ss <= tgtIndex)
+ && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
+ tmpVal = (int16_t) ((vpdTableI[i]
+ [sizeCurrVpdTable -
+ 1] + (ss - maxIndex +
+ 1) * vpdStep));
+ pPDADCValues[k++] = (u8) ((tmpVal >
+ 255) ? 255 : tmpVal);
+ ss++;
+ }
+ }
+ }
+
+ while (i < AR5416_PD_GAINS_IN_MASK) {
+ pPdGainBoundaries[i] = pPdGainBoundaries[i - 1];
+ i++;
+ }
+
+ while (k < AR5416_NUM_PDADC_VALUES) {
+ pPDADCValues[k] = pPDADCValues[k - 1];
+ k++;
+ }
+ return;
+}
+
+static inline bool
+ath9k_hw_set_power_cal_table(struct ath_hal *ah,
+ struct ar5416_eeprom *pEepData,
+ struct ath9k_channel *chan,
+ int16_t *pTxPowerIndexOffset)
+{
+ struct cal_data_per_freq *pRawDataset;
+ u8 *pCalBChans = NULL;
+ u16 pdGainOverlap_t2;
+ static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
+ u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+ u16 numPiers, i, j;
+ int16_t tMinCalPower;
+ u16 numXpdGain, xpdMask;
+ u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
+ u32 reg32, regOffset, regChainOffset;
+ int16_t modalIdx;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
+ xpdMask = pEepData->modalHeader[modalIdx].xpdGain;
+
+ if ((pEepData->baseEepHeader.
+ version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ pdGainOverlap_t2 =
+ pEepData->modalHeader[modalIdx].pdGainOverlap;
+ } else {
+ pdGainOverlap_t2 =
+ (u16) (MS
+ (REG_READ(ah, AR_PHY_TPCRG5),
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
+ }
+
+ if (IS_CHAN_2GHZ(chan)) {
+ pCalBChans = pEepData->calFreqPier2G;
+ numPiers = AR5416_NUM_2G_CAL_PIERS;
+ } else {
+ pCalBChans = pEepData->calFreqPier5G;
+ numPiers = AR5416_NUM_5G_CAL_PIERS;
+ }
+
+ numXpdGain = 0;
+
+ for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
+ if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
+ if (numXpdGain >= AR5416_NUM_PD_GAINS)
+ break;
+ xpdGainValues[numXpdGain] =
+ (u16) (AR5416_PD_GAINS_IN_MASK - i);
+ numXpdGain++;
+ }
+ }
+
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
+ (numXpdGain - 1) & 0x3);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
+ xpdGainValues[0]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
+ xpdGainValues[1]);
+ REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
+ xpdGainValues[2]);
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ if (AR_SREV_5416_V20_OR_LATER(ah) &&
+ (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5)
+ && (i != 0)) {
+ regChainOffset = (i == 1) ? 0x2000 : 0x1000;
+ } else
+ regChainOffset = i * 0x1000;
+ if (pEepData->baseEepHeader.txMask & (1 << i)) {
+ if (IS_CHAN_2GHZ(chan))
+ pRawDataset = pEepData->calPierData2G[i];
+ else
+ pRawDataset = pEepData->calPierData5G[i];
+
+ ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
+ pRawDataset,
+ pCalBChans,
+ numPiers,
+ pdGainOverlap_t2,
+ &tMinCalPower,
+ gainBoundaries,
+ pdadcValues,
+ numXpdGain);
+
+ if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+
+ REG_WRITE(ah,
+ AR_PHY_TPCRG5 + regChainOffset,
+ SM(pdGainOverlap_t2,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+ | SM(gainBoundaries[0],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+ | SM(gainBoundaries[1],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+ | SM(gainBoundaries[2],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+ | SM(gainBoundaries[3],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+ }
+
+ regOffset =
+ AR_PHY_BASE + (672 << 2) + regChainOffset;
+ for (j = 0; j < 32; j++) {
+ reg32 =
+ ((pdadcValues[4 * j + 0] & 0xFF) << 0)
+ | ((pdadcValues[4 * j + 1] & 0xFF) <<
+ 8) | ((pdadcValues[4 * j + 2] &
+ 0xFF) << 16) |
+ ((pdadcValues[4 * j + 3] & 0xFF) <<
+ 24);
+ REG_WRITE(ah, regOffset, reg32);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
+ "PDADC (%d,%4x): %4.4x %8.8x\n",
+ i, regChainOffset, regOffset,
+ reg32);
+ DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
+ "PDADC: Chain %d | PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d | PDADC %3d Value %3d | "
+ "PDADC %3d Value %3d |\n",
+ i, 4 * j, pdadcValues[4 * j],
+ 4 * j + 1, pdadcValues[4 * j + 1],
+ 4 * j + 2, pdadcValues[4 * j + 2],
+ 4 * j + 3,
+ pdadcValues[4 * j + 3]);
+
+ regOffset += 4;
+ }
+ }
+ }
+ *pTxPowerIndexOffset = 0;
+
+ return true;
+}
+
+void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u8 i;
+
+ if (ah->ah_isPciExpress != true)
+ return;
+
+ if (ah->ah_config.pcie_powersave_enable == 2)
+ return;
+
+ if (restore)
+ return;
+
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) {
+ REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0),
+ INI_RA(&ahp->ah_iniPcieSerdes, i, 1));
+ }
+ udelay(1000);
+ } else if (AR_SREV_9280(ah)
+ && (ah->ah_macRev == AR_SREV_REVISION_9280_10)) {
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
+
+ if (ah->ah_config.pcie_clock_req)
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
+ else
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
+
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
+
+ REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+ udelay(1000);
+ } else {
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+ REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
+ REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+ }
+
+ REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+
+ if (ah->ah_config.pcie_waen) {
+ REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen);
+ } else {
+ if (AR_SREV_9280(ah))
+ REG_WRITE(ah, AR_WA, 0x0040073f);
+ else
+ REG_WRITE(ah, AR_WA, 0x0000073f);
+ }
+}
+
+static inline void
+ath9k_hw_get_legacy_target_powers(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ struct cal_target_power_leg *powInfo,
+ u16 numChannels,
+ struct cal_target_power_leg *pNewPower,
+ u16 numRates,
+ bool isExtTarget)
+{
+ u16 clo, chi;
+ int i;
+ int matchIndex = -1, lowIndex = -1;
+ u16 freq;
+ struct chan_centers centers;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+ freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
+
+ if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
+ IS_CHAN_2GHZ(chan))) {
+ matchIndex = 0;
+ } else {
+ for (i = 0; (i < numChannels)
+ && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+ if (freq ==
+ ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan))) {
+ matchIndex = i;
+ break;
+ } else if ((freq <
+ ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan)))
+ && (freq >
+ ath9k_hw_fbin2freq(powInfo[i - 1].
+ bChannel,
+ IS_CHAN_2GHZ
+ (chan)))) {
+ lowIndex = i - 1;
+ break;
+ }
+ }
+ if ((matchIndex == -1) && (lowIndex == -1))
+ matchIndex = i - 1;
+ }
+
+ if (matchIndex != -1) {
+ *pNewPower = powInfo[matchIndex];
+ } else {
+ clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+ IS_CHAN_2GHZ(chan));
+ chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+ IS_CHAN_2GHZ(chan));
+
+ for (i = 0; i < numRates; i++) {
+ pNewPower->tPow2x[i] =
+ (u8) ath9k_hw_interpolate(freq, clo, chi,
+ powInfo
+ [lowIndex].
+ tPow2x[i],
+ powInfo
+ [lowIndex +
+ 1].tPow2x[i]);
+ }
+ }
+}
+
+static inline void
+ath9k_hw_get_target_powers(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ struct cal_target_power_ht *powInfo,
+ u16 numChannels,
+ struct cal_target_power_ht *pNewPower,
+ u16 numRates,
+ bool isHt40Target)
+{
+ u16 clo, chi;
+ int i;
+ int matchIndex = -1, lowIndex = -1;
+ u16 freq;
+ struct chan_centers centers;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+ freq = isHt40Target ? centers.synth_center : centers.ctl_center;
+
+ if (freq <=
+ ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
+ matchIndex = 0;
+ } else {
+ for (i = 0; (i < numChannels)
+ && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+ if (freq ==
+ ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan))) {
+ matchIndex = i;
+ break;
+ } else
+ if ((freq <
+ ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan)))
+ && (freq >
+ ath9k_hw_fbin2freq(powInfo[i - 1].
+ bChannel,
+ IS_CHAN_2GHZ
+ (chan)))) {
+ lowIndex = i - 1;
+ break;
+ }
+ }
+ if ((matchIndex == -1) && (lowIndex == -1))
+ matchIndex = i - 1;
+ }
+
+ if (matchIndex != -1) {
+ *pNewPower = powInfo[matchIndex];
+ } else {
+ clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
+ IS_CHAN_2GHZ(chan));
+ chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
+ IS_CHAN_2GHZ(chan));
+
+ for (i = 0; i < numRates; i++) {
+ pNewPower->tPow2x[i] =
+ (u8) ath9k_hw_interpolate(freq, clo, chi,
+ powInfo
+ [lowIndex].
+ tPow2x[i],
+ powInfo
+ [lowIndex +
+ 1].tPow2x[i]);
+ }
+ }
+}
+
+static inline u16
+ath9k_hw_get_max_edge_power(u16 freq,
+ struct cal_ctl_edges *pRdEdgesPower,
+ bool is2GHz)
+{
+ u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ int i;
+
+ for (i = 0; (i < AR5416_NUM_BAND_EDGES)
+ && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
+ if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
+ is2GHz)) {
+ twiceMaxEdgePower = pRdEdgesPower[i].tPower;
+ break;
+ } else if ((i > 0)
+ && (freq <
+ ath9k_hw_fbin2freq(pRdEdgesPower[i].
+ bChannel, is2GHz))) {
+ if (ath9k_hw_fbin2freq
+ (pRdEdgesPower[i - 1].bChannel, is2GHz) < freq
+ && pRdEdgesPower[i - 1].flag) {
+ twiceMaxEdgePower =
+ pRdEdgesPower[i - 1].tPower;
+ }
+ break;
+ }
+ }
+ return twiceMaxEdgePower;
+}
+
+static inline bool
+ath9k_hw_set_power_per_rate_table(struct ath_hal *ah,
+ struct ar5416_eeprom *pEepData,
+ struct ath9k_channel *chan,
+ int16_t *ratesArray,
+ u16 cfgCtl,
+ u8 AntennaReduction,
+ u8 twiceMaxRegulatoryPower,
+ u8 powerLimit)
+{
+ u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+ static const u16 tpScaleReductionTable[5] =
+ { 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
+
+ int i;
+ int8_t twiceLargestAntenna;
+ struct cal_ctl_data *rep;
+ struct cal_target_power_leg targetPowerOfdm, targetPowerCck = {
+ 0, { 0, 0, 0, 0}
+ };
+ struct cal_target_power_leg targetPowerOfdmExt = {
+ 0, { 0, 0, 0, 0} }, targetPowerCckExt = {
+ 0, { 0, 0, 0, 0 }
+ };
+ struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {
+ 0, {0, 0, 0, 0}
+ };
+ u8 scaledPower = 0, minCtlPower, maxRegAllowedPower;
+ u16 ctlModesFor11a[] =
+ { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 };
+ u16 ctlModesFor11g[] =
+ { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT,
+ CTL_2GHT40
+ };
+ u16 numCtlModes, *pCtlMode, ctlMode, freq;
+ struct chan_centers centers;
+ int tx_chainmask;
+ u8 twiceMinEdgePower;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ tx_chainmask = ahp->ah_txchainmask;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ twiceLargestAntenna = max(
+ pEepData->modalHeader
+ [IS_CHAN_2GHZ(chan)].antennaGainCh[0],
+ pEepData->modalHeader
+ [IS_CHAN_2GHZ(chan)].antennaGainCh[1]);
+
+ twiceLargestAntenna = max((u8) twiceLargestAntenna,
+ pEepData->modalHeader
+ [IS_CHAN_2GHZ(chan)].antennaGainCh[2]);
+
+ twiceLargestAntenna =
+ (int8_t) min(AntennaReduction - twiceLargestAntenna, 0);
+
+ maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
+ if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) {
+ maxRegAllowedPower -=
+ (tpScaleReductionTable[(ah->ah_tpScale)] * 2);
+ }
+
+ scaledPower = min(powerLimit, maxRegAllowedPower);
+
+ switch (ar5416_get_ntxchains(tx_chainmask)) {
+ case 1:
+ break;
+ case 2:
+ scaledPower -=
+ pEepData->modalHeader[IS_CHAN_2GHZ(chan)].
+ pwrDecreaseFor2Chain;
+ break;
+ case 3:
+ scaledPower -=
+ pEepData->modalHeader[IS_CHAN_2GHZ(chan)].
+ pwrDecreaseFor3Chain;
+ break;
+ }
+
+ scaledPower = max(0, (int32_t) scaledPower);
+
+ if (IS_CHAN_2GHZ(chan)) {
+ numCtlModes =
+ ARRAY_SIZE(ctlModesFor11g) -
+ SUB_NUM_CTL_MODES_AT_2G_40;
+ pCtlMode = ctlModesFor11g;
+
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->
+ calTargetPowerCck,
+ AR5416_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCck, 4,
+ false);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->
+ calTargetPower2G,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdm, 4,
+ false);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower2GHT20,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerHt20, 8, false);
+
+ if (IS_CHAN_HT40(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11g);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->
+ calTargetPower2GHT40,
+ AR5416_NUM_2G_40_TARGET_POWERS,
+ &targetPowerHt40, 8,
+ true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->
+ calTargetPowerCck,
+ AR5416_NUM_2G_CCK_TARGET_POWERS,
+ &targetPowerCckExt,
+ 4, true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->
+ calTargetPower2G,
+ AR5416_NUM_2G_20_TARGET_POWERS,
+ &targetPowerOfdmExt,
+ 4, true);
+ }
+ } else {
+
+ numCtlModes =
+ ARRAY_SIZE(ctlModesFor11a) -
+ SUB_NUM_CTL_MODES_AT_5G_40;
+ pCtlMode = ctlModesFor11a;
+
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->
+ calTargetPower5G,
+ AR5416_NUM_5G_20_TARGET_POWERS,
+ &targetPowerOfdm, 4,
+ false);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->calTargetPower5GHT20,
+ AR5416_NUM_5G_20_TARGET_POWERS,
+ &targetPowerHt20, 8, false);
+
+ if (IS_CHAN_HT40(chan)) {
+ numCtlModes = ARRAY_SIZE(ctlModesFor11a);
+ ath9k_hw_get_target_powers(ah, chan,
+ pEepData->
+ calTargetPower5GHT40,
+ AR5416_NUM_5G_40_TARGET_POWERS,
+ &targetPowerHt40, 8,
+ true);
+ ath9k_hw_get_legacy_target_powers(ah, chan,
+ pEepData->
+ calTargetPower5G,
+ AR5416_NUM_5G_20_TARGET_POWERS,
+ &targetPowerOfdmExt,
+ 4, true);
+ }
+ }
+
+ for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
+ bool isHt40CtlMode =
+ (pCtlMode[ctlMode] == CTL_5GHT40)
+ || (pCtlMode[ctlMode] == CTL_2GHT40);
+ if (isHt40CtlMode)
+ freq = centers.synth_center;
+ else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
+ freq = centers.ext_center;
+ else
+ freq = centers.ctl_center;
+
+ if (ar5416_get_eep_ver(ahp) == 14
+ && ar5416_get_eep_rev(ahp) <= 2)
+ twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
+ "EXT_ADDITIVE %d\n",
+ ctlMode, numCtlModes, isHt40CtlMode,
+ (pCtlMode[ctlMode] & EXT_ADDITIVE));
+
+ for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i];
+ i++) {
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ " LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
+ "pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
+ "chan %d\n",
+ i, cfgCtl, pCtlMode[ctlMode],
+ pEepData->ctlIndex[i], chan->channel);
+
+ if ((((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ pEepData->ctlIndex[i])
+ ||
+ (((cfgCtl & ~CTL_MODE_M) |
+ (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+ ((pEepData->
+ ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) {
+ rep = &(pEepData->ctlData[i]);
+
+ twiceMinEdgePower =
+ ath9k_hw_get_max_edge_power(freq,
+ rep->
+ ctlEdges
+ [ar5416_get_ntxchains
+ (tx_chainmask)
+ - 1],
+ IS_CHAN_2GHZ
+ (chan));
+
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ " MATCH-EE_IDX %d: ch %d is2 %d "
+ "2xMinEdge %d chainmask %d chains %d\n",
+ i, freq, IS_CHAN_2GHZ(chan),
+ twiceMinEdgePower, tx_chainmask,
+ ar5416_get_ntxchains
+ (tx_chainmask));
+ if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+ twiceMaxEdgePower =
+ min(twiceMaxEdgePower,
+ twiceMinEdgePower);
+ } else {
+ twiceMaxEdgePower =
+ twiceMinEdgePower;
+ break;
+ }
+ }
+ }
+
+ minCtlPower = min(twiceMaxEdgePower, scaledPower);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ " SEL-Min ctlMode %d pCtlMode %d "
+ "2xMaxEdge %d sP %d minCtlPwr %d\n",
+ ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+ scaledPower, minCtlPower);
+
+ switch (pCtlMode[ctlMode]) {
+ case CTL_11B:
+ for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x);
+ i++) {
+ targetPowerCck.tPow2x[i] =
+ min(targetPowerCck.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11A:
+ case CTL_11G:
+ for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x);
+ i++) {
+ targetPowerOfdm.tPow2x[i] =
+ min(targetPowerOfdm.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_5GHT20:
+ case CTL_2GHT20:
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x);
+ i++) {
+ targetPowerHt20.tPow2x[i] =
+ min(targetPowerHt20.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ case CTL_11B_EXT:
+ targetPowerCckExt.tPow2x[0] =
+ min(targetPowerCckExt.tPow2x[0], minCtlPower);
+ break;
+ case CTL_11A_EXT:
+ case CTL_11G_EXT:
+ targetPowerOfdmExt.tPow2x[0] =
+ min(targetPowerOfdmExt.tPow2x[0], minCtlPower);
+ break;
+ case CTL_5GHT40:
+ case CTL_2GHT40:
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x);
+ i++) {
+ targetPowerHt40.tPow2x[i] =
+ min(targetPowerHt40.tPow2x[i],
+ minCtlPower);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] =
+ ratesArray[rate18mb] = ratesArray[rate24mb] =
+ targetPowerOfdm.tPow2x[0];
+ ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
+ ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
+ ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
+ ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
+
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
+ ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
+
+ if (IS_CHAN_2GHZ(chan)) {
+ ratesArray[rate1l] = targetPowerCck.tPow2x[0];
+ ratesArray[rate2s] = ratesArray[rate2l] =
+ targetPowerCck.tPow2x[1];
+ ratesArray[rate5_5s] = ratesArray[rate5_5l] =
+ targetPowerCck.tPow2x[2];
+ ;
+ ratesArray[rate11s] = ratesArray[rate11l] =
+ targetPowerCck.tPow2x[3];
+ ;
+ }
+ if (IS_CHAN_HT40(chan)) {
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+ ratesArray[rateHt40_0 + i] =
+ targetPowerHt40.tPow2x[i];
+ }
+ ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
+ ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+ if (IS_CHAN_2GHZ(chan)) {
+ ratesArray[rateExtCck] =
+ targetPowerCckExt.tPow2x[0];
+ }
+ }
+ return true;
+}
+
+static int
+ath9k_hw_set_txpower(struct ath_hal *ah,
+ struct ar5416_eeprom *pEepData,
+ struct ath9k_channel *chan,
+ u16 cfgCtl,
+ u8 twiceAntennaReduction,
+ u8 twiceMaxRegulatoryPower,
+ u8 powerLimit)
+{
+ struct modal_eep_header *pModal =
+ &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
+ int16_t ratesArray[Ar5416RateSize];
+ int16_t txPowerIndexOffset = 0;
+ u8 ht40PowerIncForPdadc = 2;
+ int i;
+
+ memset(ratesArray, 0, sizeof(ratesArray));
+
+ if ((pEepData->baseEepHeader.
+ version & AR5416_EEP_VER_MINOR_MASK) >=
+ AR5416_EEP_MINOR_VER_2) {
+ ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
+ }
+
+ if (!ath9k_hw_set_power_per_rate_table(ah, pEepData, chan,
+ &ratesArray[0], cfgCtl,
+ twiceAntennaReduction,
+ twiceMaxRegulatoryPower,
+ powerLimit)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "ath9k_hw_set_txpower: unable to set "
+ "tx power per rate table\n");
+ return -EIO;
+ }
+
+ if (!ath9k_hw_set_power_cal_table
+ (ah, pEepData, chan, &txPowerIndexOffset)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "ath9k_hw_set_txpower: unable to set power table\n");
+ return -EIO;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
+ ratesArray[i] =
+ (int16_t) (txPowerIndexOffset + ratesArray[i]);
+ if (ratesArray[i] > AR5416_MAX_RATE_POWER)
+ ratesArray[i] = AR5416_MAX_RATE_POWER;
+ }
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ for (i = 0; i < Ar5416RateSize; i++)
+ ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2;
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
+ ATH9K_POW_SM(ratesArray[rate18mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate12mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate9mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate6mb], 0)
+ );
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
+ ATH9K_POW_SM(ratesArray[rate54mb], 24)
+ | ATH9K_POW_SM(ratesArray[rate48mb], 16)
+ | ATH9K_POW_SM(ratesArray[rate36mb], 8)
+ | ATH9K_POW_SM(ratesArray[rate24mb], 0)
+ );
+
+ if (IS_CHAN_2GHZ(chan)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+ ATH9K_POW_SM(ratesArray[rate2s], 24)
+ | ATH9K_POW_SM(ratesArray[rate2l], 16)
+ | ATH9K_POW_SM(ratesArray[rateXr], 8)
+ | ATH9K_POW_SM(ratesArray[rate1l], 0)
+ );
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+ ATH9K_POW_SM(ratesArray[rate11s], 24)
+ | ATH9K_POW_SM(ratesArray[rate11l], 16)
+ | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+ | ATH9K_POW_SM(ratesArray[rate5_5l], 0)
+ );
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
+ ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)
+ );
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
+ ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
+ | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
+ | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
+ | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)
+ );
+
+ if (IS_CHAN_HT40(chan)) {
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
+ ATH9K_POW_SM(ratesArray[rateHt40_3] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_2] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_1] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_0] +
+ ht40PowerIncForPdadc, 0)
+ );
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
+ ATH9K_POW_SM(ratesArray[rateHt40_7] +
+ ht40PowerIncForPdadc, 24)
+ | ATH9K_POW_SM(ratesArray[rateHt40_6] +
+ ht40PowerIncForPdadc, 16)
+ | ATH9K_POW_SM(ratesArray[rateHt40_5] +
+ ht40PowerIncForPdadc, 8)
+ | ATH9K_POW_SM(ratesArray[rateHt40_4] +
+ ht40PowerIncForPdadc, 0)
+ );
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+ ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+ | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+ | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+ | ATH9K_POW_SM(ratesArray[rateDupCck], 0)
+ );
+ }
+
+ REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
+ ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
+ | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)
+ );
+
+ i = rate6mb;
+ if (IS_CHAN_HT40(chan))
+ i = rateHt40_0;
+ else if (IS_CHAN_HT20(chan))
+ i = rateHt20_0;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ah->ah_maxPowerLevel =
+ ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2;
+ else
+ ah->ah_maxPowerLevel = ratesArray[i];
+
+ return 0;
+}
+
+static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah,
+ u32 coef_scaled,
+ u32 *coef_mantissa,
+ u32 *coef_exponent)
+{
+ u32 coef_exp, coef_man;
+
+ for (coef_exp = 31; coef_exp > 0; coef_exp--)
+ if ((coef_scaled >> coef_exp) & 0x1)
+ break;
+
+ coef_exp = 14 - (coef_exp - COEF_SCALE_S);
+
+ coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1));
+
+ *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp);
+ *coef_exponent = coef_exp - 16;
+}
+
+static void
+ath9k_hw_set_delta_slope(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ u32 coef_scaled, ds_coef_exp, ds_coef_man;
+ u32 clockMhzScaled = 0x64000000;
+ struct chan_centers centers;
+
+ if (IS_CHAN_HALF_RATE(chan))
+ clockMhzScaled = clockMhzScaled >> 1;
+ else if (IS_CHAN_QUARTER_RATE(chan))
+ clockMhzScaled = clockMhzScaled >> 2;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+ coef_scaled = clockMhzScaled / centers.synth_center;
+
+ ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+ &ds_coef_exp);
+
+ REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+ AR_PHY_TIMING3_DSC_MAN, ds_coef_man);
+ REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+ AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);
+
+ coef_scaled = (9 * coef_scaled) / 10;
+
+ ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+ &ds_coef_exp);
+
+ REG_RMW_FIELD(ah, AR_PHY_HALFGI,
+ AR_PHY_HALFGI_DSC_MAN, ds_coef_man);
+ REG_RMW_FIELD(ah, AR_PHY_HALFGI,
+ AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);
+}
+
+static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ int bb_spur = AR_NO_SPUR;
+ int freq;
+ int bin, cur_bin;
+ int bb_spur_off, spur_subchannel_sd;
+ int spur_freq_sd;
+ int spur_delta_phase;
+ int denominator;
+ int upper, lower, cur_vit_mask;
+ int tmp, newVal;
+ int i;
+ int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
+ AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
+ };
+ int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
+ AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
+ };
+ int inc[4] = { 0, 100, 0, 0 };
+ struct chan_centers centers;
+
+ int8_t mask_m[123];
+ int8_t mask_p[123];
+ int8_t mask_amt;
+ int tmp_mask;
+ int cur_bb_spur;
+ bool is2GHz = IS_CHAN_2GHZ(chan);
+
+ memset(&mask_m, 0, sizeof(int8_t) * 123);
+ memset(&mask_p, 0, sizeof(int8_t) * 123);
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+ freq = centers.synth_center;
+
+ ah->ah_config.spurmode = SPUR_ENABLE_EEPROM;
+ for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+ cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz);
+
+ if (is2GHz)
+ cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ;
+ else
+ cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ;
+
+ if (AR_NO_SPUR == cur_bb_spur)
+ break;
+ cur_bb_spur = cur_bb_spur - freq;
+
+ if (IS_CHAN_HT40(chan)) {
+ if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) &&
+ (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) {
+ bb_spur = cur_bb_spur;
+ break;
+ }
+ } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) &&
+ (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) {
+ bb_spur = cur_bb_spur;
+ break;
+ }
+ }
+
+ if (AR_NO_SPUR == bb_spur) {
+ REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
+ AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
+ return;
+ } else {
+ REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
+ AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
+ }
+
+ bin = bb_spur * 320;
+
+ tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
+
+ newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
+ AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
+ AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
+ AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
+ REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal);
+
+ newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
+ AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
+ AR_PHY_SPUR_REG_MASK_RATE_SELECT |
+ AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
+ SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
+ REG_WRITE(ah, AR_PHY_SPUR_REG, newVal);
+
+ if (IS_CHAN_HT40(chan)) {
+ if (bb_spur < 0) {
+ spur_subchannel_sd = 1;
+ bb_spur_off = bb_spur + 10;
+ } else {
+ spur_subchannel_sd = 0;
+ bb_spur_off = bb_spur - 10;
+ }
+ } else {
+ spur_subchannel_sd = 0;
+ bb_spur_off = bb_spur;
+ }
+
+ if (IS_CHAN_HT40(chan))
+ spur_delta_phase =
+ ((bb_spur * 262144) /
+ 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+ else
+ spur_delta_phase =
+ ((bb_spur * 524288) /
+ 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+
+ denominator = IS_CHAN_2GHZ(chan) ? 44 : 40;
+ spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff;
+
+ newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
+ SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
+ SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
+ REG_WRITE(ah, AR_PHY_TIMING11, newVal);
+
+ newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S;
+ REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal);
+
+ cur_bin = -6000;
+ upper = bin + 100;
+ lower = bin - 100;
+
+ for (i = 0; i < 4; i++) {
+ int pilot_mask = 0;
+ int chan_mask = 0;
+ int bp = 0;
+ for (bp = 0; bp < 30; bp++) {
+ if ((cur_bin > lower) && (cur_bin < upper)) {
+ pilot_mask = pilot_mask | 0x1 << bp;
+ chan_mask = chan_mask | 0x1 << bp;
+ }
+ cur_bin += 100;
+ }
+ cur_bin += inc[i];
+ REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
+ REG_WRITE(ah, chan_mask_reg[i], chan_mask);
+ }
+
+ cur_vit_mask = 6100;
+ upper = bin + 120;
+ lower = bin - 120;
+
+ for (i = 0; i < 123; i++) {
+ if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
+
+ /* workaround for gcc bug #37014 */
+ volatile int tmp = abs(cur_vit_mask - bin);
+
+ if (tmp < 75)
+ mask_amt = 1;
+ else
+ mask_amt = 0;
+ if (cur_vit_mask < 0)
+ mask_m[abs(cur_vit_mask / 100)] = mask_amt;
+ else
+ mask_p[cur_vit_mask / 100] = mask_amt;
+ }
+ cur_vit_mask -= 100;
+ }
+
+ tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
+ | (mask_m[48] << 26) | (mask_m[49] << 24)
+ | (mask_m[50] << 22) | (mask_m[51] << 20)
+ | (mask_m[52] << 18) | (mask_m[53] << 16)
+ | (mask_m[54] << 14) | (mask_m[55] << 12)
+ | (mask_m[56] << 10) | (mask_m[57] << 8)
+ | (mask_m[58] << 6) | (mask_m[59] << 4)
+ | (mask_m[60] << 2) | (mask_m[61] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
+ REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
+
+ tmp_mask = (mask_m[31] << 28)
+ | (mask_m[32] << 26) | (mask_m[33] << 24)
+ | (mask_m[34] << 22) | (mask_m[35] << 20)
+ | (mask_m[36] << 18) | (mask_m[37] << 16)
+ | (mask_m[48] << 14) | (mask_m[39] << 12)
+ | (mask_m[40] << 10) | (mask_m[41] << 8)
+ | (mask_m[42] << 6) | (mask_m[43] << 4)
+ | (mask_m[44] << 2) | (mask_m[45] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
+
+ tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
+ | (mask_m[18] << 26) | (mask_m[18] << 24)
+ | (mask_m[20] << 22) | (mask_m[20] << 20)
+ | (mask_m[22] << 18) | (mask_m[22] << 16)
+ | (mask_m[24] << 14) | (mask_m[24] << 12)
+ | (mask_m[25] << 10) | (mask_m[26] << 8)
+ | (mask_m[27] << 6) | (mask_m[28] << 4)
+ | (mask_m[29] << 2) | (mask_m[30] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
+
+ tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
+ | (mask_m[2] << 26) | (mask_m[3] << 24)
+ | (mask_m[4] << 22) | (mask_m[5] << 20)
+ | (mask_m[6] << 18) | (mask_m[7] << 16)
+ | (mask_m[8] << 14) | (mask_m[9] << 12)
+ | (mask_m[10] << 10) | (mask_m[11] << 8)
+ | (mask_m[12] << 6) | (mask_m[13] << 4)
+ | (mask_m[14] << 2) | (mask_m[15] << 0);
+ REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
+
+ tmp_mask = (mask_p[15] << 28)
+ | (mask_p[14] << 26) | (mask_p[13] << 24)
+ | (mask_p[12] << 22) | (mask_p[11] << 20)
+ | (mask_p[10] << 18) | (mask_p[9] << 16)
+ | (mask_p[8] << 14) | (mask_p[7] << 12)
+ | (mask_p[6] << 10) | (mask_p[5] << 8)
+ | (mask_p[4] << 6) | (mask_p[3] << 4)
+ | (mask_p[2] << 2) | (mask_p[1] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
+
+ tmp_mask = (mask_p[30] << 28)
+ | (mask_p[29] << 26) | (mask_p[28] << 24)
+ | (mask_p[27] << 22) | (mask_p[26] << 20)
+ | (mask_p[25] << 18) | (mask_p[24] << 16)
+ | (mask_p[23] << 14) | (mask_p[22] << 12)
+ | (mask_p[21] << 10) | (mask_p[20] << 8)
+ | (mask_p[19] << 6) | (mask_p[18] << 4)
+ | (mask_p[17] << 2) | (mask_p[16] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
+
+ tmp_mask = (mask_p[45] << 28)
+ | (mask_p[44] << 26) | (mask_p[43] << 24)
+ | (mask_p[42] << 22) | (mask_p[41] << 20)
+ | (mask_p[40] << 18) | (mask_p[39] << 16)
+ | (mask_p[38] << 14) | (mask_p[37] << 12)
+ | (mask_p[36] << 10) | (mask_p[35] << 8)
+ | (mask_p[34] << 6) | (mask_p[33] << 4)
+ | (mask_p[32] << 2) | (mask_p[31] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
+
+ tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
+ | (mask_p[59] << 26) | (mask_p[58] << 24)
+ | (mask_p[57] << 22) | (mask_p[56] << 20)
+ | (mask_p[55] << 18) | (mask_p[54] << 16)
+ | (mask_p[53] << 14) | (mask_p[52] << 12)
+ | (mask_p[51] << 10) | (mask_p[50] << 8)
+ | (mask_p[49] << 6) | (mask_p[48] << 4)
+ | (mask_p[47] << 2) | (mask_p[46] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+}
+
+static void ath9k_hw_spur_mitigate(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ int bb_spur = AR_NO_SPUR;
+ int bin, cur_bin;
+ int spur_freq_sd;
+ int spur_delta_phase;
+ int denominator;
+ int upper, lower, cur_vit_mask;
+ int tmp, new;
+ int i;
+ int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
+ AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
+ };
+ int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
+ AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
+ };
+ int inc[4] = { 0, 100, 0, 0 };
+
+ int8_t mask_m[123];
+ int8_t mask_p[123];
+ int8_t mask_amt;
+ int tmp_mask;
+ int cur_bb_spur;
+ bool is2GHz = IS_CHAN_2GHZ(chan);
+
+ memset(&mask_m, 0, sizeof(int8_t) * 123);
+ memset(&mask_p, 0, sizeof(int8_t) * 123);
+
+ for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+ cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz);
+ if (AR_NO_SPUR == cur_bb_spur)
+ break;
+ cur_bb_spur = cur_bb_spur - (chan->channel * 10);
+ if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) {
+ bb_spur = cur_bb_spur;
+ break;
+ }
+ }
+
+ if (AR_NO_SPUR == bb_spur)
+ return;
+
+ bin = bb_spur * 32;
+
+ tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
+ new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
+ AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
+ AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
+ AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
+
+ REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new);
+
+ new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
+ AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
+ AR_PHY_SPUR_REG_MASK_RATE_SELECT |
+ AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
+ SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
+ REG_WRITE(ah, AR_PHY_SPUR_REG, new);
+
+ spur_delta_phase = ((bb_spur * 524288) / 100) &
+ AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+
+ denominator = IS_CHAN_2GHZ(chan) ? 440 : 400;
+ spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff;
+
+ new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
+ SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
+ SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
+ REG_WRITE(ah, AR_PHY_TIMING11, new);
+
+ cur_bin = -6000;
+ upper = bin + 100;
+ lower = bin - 100;
+
+ for (i = 0; i < 4; i++) {
+ int pilot_mask = 0;
+ int chan_mask = 0;
+ int bp = 0;
+ for (bp = 0; bp < 30; bp++) {
+ if ((cur_bin > lower) && (cur_bin < upper)) {
+ pilot_mask = pilot_mask | 0x1 << bp;
+ chan_mask = chan_mask | 0x1 << bp;
+ }
+ cur_bin += 100;
+ }
+ cur_bin += inc[i];
+ REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
+ REG_WRITE(ah, chan_mask_reg[i], chan_mask);
+ }
+
+ cur_vit_mask = 6100;
+ upper = bin + 120;
+ lower = bin - 120;
+
+ for (i = 0; i < 123; i++) {
+ if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
+
+ /* workaround for gcc bug #37014 */
+ volatile int tmp = abs(cur_vit_mask - bin);
+
+ if (tmp < 75)
+ mask_amt = 1;
+ else
+ mask_amt = 0;
+ if (cur_vit_mask < 0)
+ mask_m[abs(cur_vit_mask / 100)] = mask_amt;
+ else
+ mask_p[cur_vit_mask / 100] = mask_amt;
+ }
+ cur_vit_mask -= 100;
+ }
+
+ tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
+ | (mask_m[48] << 26) | (mask_m[49] << 24)
+ | (mask_m[50] << 22) | (mask_m[51] << 20)
+ | (mask_m[52] << 18) | (mask_m[53] << 16)
+ | (mask_m[54] << 14) | (mask_m[55] << 12)
+ | (mask_m[56] << 10) | (mask_m[57] << 8)
+ | (mask_m[58] << 6) | (mask_m[59] << 4)
+ | (mask_m[60] << 2) | (mask_m[61] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
+ REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
+
+ tmp_mask = (mask_m[31] << 28)
+ | (mask_m[32] << 26) | (mask_m[33] << 24)
+ | (mask_m[34] << 22) | (mask_m[35] << 20)
+ | (mask_m[36] << 18) | (mask_m[37] << 16)
+ | (mask_m[48] << 14) | (mask_m[39] << 12)
+ | (mask_m[40] << 10) | (mask_m[41] << 8)
+ | (mask_m[42] << 6) | (mask_m[43] << 4)
+ | (mask_m[44] << 2) | (mask_m[45] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
+
+ tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
+ | (mask_m[18] << 26) | (mask_m[18] << 24)
+ | (mask_m[20] << 22) | (mask_m[20] << 20)
+ | (mask_m[22] << 18) | (mask_m[22] << 16)
+ | (mask_m[24] << 14) | (mask_m[24] << 12)
+ | (mask_m[25] << 10) | (mask_m[26] << 8)
+ | (mask_m[27] << 6) | (mask_m[28] << 4)
+ | (mask_m[29] << 2) | (mask_m[30] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
+
+ tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
+ | (mask_m[2] << 26) | (mask_m[3] << 24)
+ | (mask_m[4] << 22) | (mask_m[5] << 20)
+ | (mask_m[6] << 18) | (mask_m[7] << 16)
+ | (mask_m[8] << 14) | (mask_m[9] << 12)
+ | (mask_m[10] << 10) | (mask_m[11] << 8)
+ | (mask_m[12] << 6) | (mask_m[13] << 4)
+ | (mask_m[14] << 2) | (mask_m[15] << 0);
+ REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
+
+ tmp_mask = (mask_p[15] << 28)
+ | (mask_p[14] << 26) | (mask_p[13] << 24)
+ | (mask_p[12] << 22) | (mask_p[11] << 20)
+ | (mask_p[10] << 18) | (mask_p[9] << 16)
+ | (mask_p[8] << 14) | (mask_p[7] << 12)
+ | (mask_p[6] << 10) | (mask_p[5] << 8)
+ | (mask_p[4] << 6) | (mask_p[3] << 4)
+ | (mask_p[2] << 2) | (mask_p[1] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
+
+ tmp_mask = (mask_p[30] << 28)
+ | (mask_p[29] << 26) | (mask_p[28] << 24)
+ | (mask_p[27] << 22) | (mask_p[26] << 20)
+ | (mask_p[25] << 18) | (mask_p[24] << 16)
+ | (mask_p[23] << 14) | (mask_p[22] << 12)
+ | (mask_p[21] << 10) | (mask_p[20] << 8)
+ | (mask_p[19] << 6) | (mask_p[18] << 4)
+ | (mask_p[17] << 2) | (mask_p[16] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
+
+ tmp_mask = (mask_p[45] << 28)
+ | (mask_p[44] << 26) | (mask_p[43] << 24)
+ | (mask_p[42] << 22) | (mask_p[41] << 20)
+ | (mask_p[40] << 18) | (mask_p[39] << 16)
+ | (mask_p[38] << 14) | (mask_p[37] << 12)
+ | (mask_p[36] << 10) | (mask_p[35] << 8)
+ | (mask_p[34] << 6) | (mask_p[33] << 4)
+ | (mask_p[32] << 2) | (mask_p[31] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
+
+ tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
+ | (mask_p[59] << 26) | (mask_p[58] << 24)
+ | (mask_p[57] << 22) | (mask_p[56] << 20)
+ | (mask_p[55] << 18) | (mask_p[54] << 16)
+ | (mask_p[53] << 14) | (mask_p[52] << 12)
+ | (mask_p[51] << 10) | (mask_p[50] << 8)
+ | (mask_p[49] << 6) | (mask_p[48] << 4)
+ | (mask_p[47] << 2) | (mask_p[46] << 0);
+ REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
+ REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+}
+
+static inline void ath9k_hw_init_chain_masks(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int rx_chainmask, tx_chainmask;
+
+ rx_chainmask = ahp->ah_rxchainmask;
+ tx_chainmask = ahp->ah_txchainmask;
+
+ switch (rx_chainmask) {
+ case 0x5:
+ REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+ AR_PHY_SWAP_ALT_CHAIN);
+ case 0x3:
+ if (((ah)->ah_macVersion <= AR_SREV_VERSION_9160)) {
+ REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
+ REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
+ break;
+ }
+ case 0x1:
+ case 0x2:
+ if (!AR_SREV_9280(ah))
+ break;
+ case 0x7:
+ REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
+ REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
+ break;
+ default:
+ break;
+ }
+
+ REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
+ if (tx_chainmask == 0x5) {
+ REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+ AR_PHY_SWAP_ALT_CHAIN);
+ }
+ if (AR_SREV_9100(ah))
+ REG_WRITE(ah, AR_PHY_ANALOG_SWAP,
+ REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
+}
+
+static void ath9k_hw_set_addac(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct modal_eep_header *pModal;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ar5416_eeprom *eep = &ahp->ah_eeprom;
+ u8 biaslevel;
+
+ if (ah->ah_macVersion != AR_SREV_VERSION_9160)
+ return;
+
+ if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7)
+ return;
+
+ pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]);
+
+ if (pModal->xpaBiasLvl != 0xff) {
+ biaslevel = pModal->xpaBiasLvl;
+ } else {
+
+ u16 resetFreqBin, freqBin, freqCount = 0;
+ struct chan_centers centers;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+ resetFreqBin =
+ FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan));
+ freqBin = pModal->xpaBiasLvlFreq[0] & 0xff;
+ biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14);
+
+ freqCount++;
+
+ while (freqCount < 3) {
+ if (pModal->xpaBiasLvlFreq[freqCount] == 0x0)
+ break;
+
+ freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff;
+ if (resetFreqBin >= freqBin) {
+ biaslevel =
+ (u8) (pModal->
+ xpaBiasLvlFreq[freqCount]
+ >> 14);
+ } else {
+ break;
+ }
+ freqCount++;
+ }
+ }
+
+ if (IS_CHAN_2GHZ(chan)) {
+ INI_RA(&ahp->ah_iniAddac, 7, 1) =
+ (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel
+ << 3;
+ } else {
+ INI_RA(&ahp->ah_iniAddac, 6, 1) =
+ (INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel
+ << 6;
+ }
+}
+
+static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks)
+{
+ if (ah->ah_curchan != NULL)
+ return clks /
+ CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)];
+ else
+ return clks / CLOCK_RATE[ATH9K_MODE_11B];
+}
+
+static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks)
+{
+ struct ath9k_channel *chan = ah->ah_curchan;
+
+ if (chan && IS_CHAN_HT40(chan))
+ return ath9k_hw_mac_usec(ah, clks) / 2;
+ else
+ return ath9k_hw_mac_usec(ah, clks);
+}
+
+static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs)
+{
+ if (ah->ah_curchan != NULL)
+ return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah,
+ ah->ah_curchan)];
+ else
+ return usecs * CLOCK_RATE[ATH9K_MODE_11B];
+}
+
+static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs)
+{
+ struct ath9k_channel *chan = ah->ah_curchan;
+
+ if (chan && IS_CHAN_HT40(chan))
+ return ath9k_hw_mac_clks(ah, usecs) * 2;
+ else
+ return ath9k_hw_mac_clks(ah, usecs);
+}
+
+static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad ack timeout %u\n",
+ __func__, us);
+ ahp->ah_acktimeout = (u32) -1;
+ return false;
+ } else {
+ REG_RMW_FIELD(ah, AR_TIME_OUT,
+ AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us));
+ ahp->ah_acktimeout = us;
+ return true;
+ }
+}
+
+static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad cts timeout %u\n",
+ __func__, us);
+ ahp->ah_ctstimeout = (u32) -1;
+ return false;
+ } else {
+ REG_RMW_FIELD(ah, AR_TIME_OUT,
+ AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us));
+ ahp->ah_ctstimeout = us;
+ return true;
+ }
+}
+static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah,
+ u32 tu)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (tu > 0xFFFF) {
+ DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
+ "%s: bad global tx timeout %u\n", __func__, tu);
+ ahp->ah_globaltxtimeout = (u32) -1;
+ return false;
+ } else {
+ REG_RMW_FIELD(ah, AR_GTXTO, AR_GTXTO_TIMEOUT_LIMIT, tu);
+ ahp->ah_globaltxtimeout = tu;
+ return true;
+ }
+}
+
+bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad slot time %u\n",
+ __func__, us);
+ ahp->ah_slottime = (u32) -1;
+ return false;
+ } else {
+ REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us));
+ ahp->ah_slottime = us;
+ return true;
+ }
+}
+
+static inline void ath9k_hw_init_user_settings(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "--AP %s ahp->ah_miscMode 0x%x\n",
+ __func__, ahp->ah_miscMode);
+ if (ahp->ah_miscMode != 0)
+ REG_WRITE(ah, AR_PCU_MISC,
+ REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode);
+ if (ahp->ah_slottime != (u32) -1)
+ ath9k_hw_setslottime(ah, ahp->ah_slottime);
+ if (ahp->ah_acktimeout != (u32) -1)
+ ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout);
+ if (ahp->ah_ctstimeout != (u32) -1)
+ ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout);
+ if (ahp->ah_globaltxtimeout != (u32) -1)
+ ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout);
+}
+
+static inline int
+ath9k_hw_process_ini(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ enum ath9k_ht_macmode macmode)
+{
+ int i, regWrites = 0;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 modesIndex, freqIndex;
+ int status;
+
+ switch (chan->chanmode) {
+ case CHANNEL_A:
+ case CHANNEL_A_HT20:
+ modesIndex = 1;
+ freqIndex = 1;
+ break;
+ case CHANNEL_A_HT40PLUS:
+ case CHANNEL_A_HT40MINUS:
+ modesIndex = 2;
+ freqIndex = 1;
+ break;
+ case CHANNEL_G:
+ case CHANNEL_G_HT20:
+ case CHANNEL_B:
+ modesIndex = 4;
+ freqIndex = 2;
+ break;
+ case CHANNEL_G_HT40PLUS:
+ case CHANNEL_G_HT40MINUS:
+ modesIndex = 3;
+ freqIndex = 2;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ REG_WRITE(ah, AR_PHY(0), 0x00000007);
+
+ REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
+
+ ath9k_hw_set_addac(ah, chan);
+
+ if (AR_SREV_5416_V22_OR_LATER(ah)) {
+ REG_WRITE_ARRAY(&ahp->ah_iniAddac, 1, regWrites);
+ } else {
+ struct ar5416IniArray temp;
+ u32 addacSize =
+ sizeof(u32) * ahp->ah_iniAddac.ia_rows *
+ ahp->ah_iniAddac.ia_columns;
+
+ memcpy(ahp->ah_addac5416_21,
+ ahp->ah_iniAddac.ia_array, addacSize);
+
+ (ahp->ah_addac5416_21)[31 *
+ ahp->ah_iniAddac.ia_columns + 1] = 0;
+
+ temp.ia_array = ahp->ah_addac5416_21;
+ temp.ia_columns = ahp->ah_iniAddac.ia_columns;
+ temp.ia_rows = ahp->ah_iniAddac.ia_rows;
+ REG_WRITE_ARRAY(&temp, 1, regWrites);
+ }
+ REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
+
+ for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
+ u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
+ u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex);
+
+#ifdef CONFIG_SLOW_ANT_DIV
+ if (ah->ah_devid == AR9280_DEVID_PCI)
+ val = ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, reg,
+ val);
+#endif
+
+ REG_WRITE(ah, reg, val);
+
+ if (reg >= 0x7800 && reg < 0x78a0
+ && ah->ah_config.analog_shiftreg) {
+ udelay(100);
+ }
+
+ DO_DELAY(regWrites);
+ }
+
+ for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) {
+ u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0);
+ u32 val = INI_RA(&ahp->ah_iniCommon, i, 1);
+
+ REG_WRITE(ah, reg, val);
+
+ if (reg >= 0x7800 && reg < 0x78a0
+ && ah->ah_config.analog_shiftreg) {
+ udelay(100);
+ }
+
+ DO_DELAY(regWrites);
+ }
+
+ ath9k_hw_write_regs(ah, modesIndex, freqIndex, regWrites);
+
+ if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) {
+ REG_WRITE_ARRAY(&ahp->ah_iniModesAdditional, modesIndex,
+ regWrites);
+ }
+
+ ath9k_hw_override_ini(ah, chan);
+ ath9k_hw_set_regs(ah, chan, macmode);
+ ath9k_hw_init_chain_masks(ah);
+
+ status = ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
+ ath9k_regd_get_ctl(ah, chan),
+ ath9k_regd_get_antenna_allowed(ah,
+ chan),
+ chan->maxRegTxPower * 2,
+ min((u32) MAX_RATE_POWER,
+ (u32) ah->ah_powerLimit));
+ if (status != 0) {
+ DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT,
+ "%s: error init'ing transmit power\n", __func__);
+ return -EIO;
+ }
+
+ if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
+ "%s: ar5416SetRfRegs failed\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static inline void ath9k_hw_setup_calibration(struct ath_hal *ah,
+ struct hal_cal_list *currCal)
+{
+ REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
+ AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
+ currCal->calData->calCountMax);
+
+ switch (currCal->calData->calType) {
+ case IQ_MISMATCH_CAL:
+ REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: starting IQ Mismatch Calibration\n",
+ __func__);
+ break;
+ case ADC_GAIN_CAL:
+ REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: starting ADC Gain Calibration\n", __func__);
+ break;
+ case ADC_DC_CAL:
+ REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: starting ADC DC Calibration\n", __func__);
+ break;
+ case ADC_DC_INIT_CAL:
+ REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: starting Init ADC DC Calibration\n",
+ __func__);
+ break;
+ }
+
+ REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+ AR_PHY_TIMING_CTRL4_DO_CAL);
+}
+
+static inline void ath9k_hw_reset_calibration(struct ath_hal *ah,
+ struct hal_cal_list *currCal)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ ath9k_hw_setup_calibration(ah, currCal);
+
+ currCal->calState = CAL_RUNNING;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ ahp->ah_Meas0.sign[i] = 0;
+ ahp->ah_Meas1.sign[i] = 0;
+ ahp->ah_Meas2.sign[i] = 0;
+ ahp->ah_Meas3.sign[i] = 0;
+ }
+
+ ahp->ah_CalSamples = 0;
+}
+
+static inline void
+ath9k_hw_per_calibration(struct ath_hal *ah,
+ struct ath9k_channel *ichan,
+ u8 rxchainmask,
+ struct hal_cal_list *currCal,
+ bool *isCalDone)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ *isCalDone = false;
+
+ if (currCal->calState == CAL_RUNNING) {
+ if (!(REG_READ(ah,
+ AR_PHY_TIMING_CTRL4(0)) &
+ AR_PHY_TIMING_CTRL4_DO_CAL)) {
+
+ currCal->calData->calCollect(ah);
+
+ ahp->ah_CalSamples++;
+
+ if (ahp->ah_CalSamples >=
+ currCal->calData->calNumSamples) {
+ int i, numChains = 0;
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ if (rxchainmask & (1 << i))
+ numChains++;
+ }
+
+ currCal->calData->calPostProc(ah,
+ numChains);
+
+ ichan->CalValid |=
+ currCal->calData->calType;
+ currCal->calState = CAL_DONE;
+ *isCalDone = true;
+ } else {
+ ath9k_hw_setup_calibration(ah, currCal);
+ }
+ }
+ } else if (!(ichan->CalValid & currCal->calData->calType)) {
+ ath9k_hw_reset_calibration(ah, currCal);
+ }
+}
+
+static inline bool ath9k_hw_run_init_cals(struct ath_hal *ah,
+ int init_cal_count)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel ichan;
+ bool isCalDone;
+ struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+ const struct hal_percal_data *calData = currCal->calData;
+ int i;
+
+ if (currCal == NULL)
+ return false;
+
+ ichan.CalValid = 0;
+
+ for (i = 0; i < init_cal_count; i++) {
+ ath9k_hw_reset_calibration(ah, currCal);
+
+ if (!ath9k_hw_wait(ah, AR_PHY_TIMING_CTRL4(0),
+ AR_PHY_TIMING_CTRL4_DO_CAL, 0)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: Cal %d failed to complete in 100ms.\n",
+ __func__, calData->calType);
+
+ ahp->ah_cal_list = ahp->ah_cal_list_last =
+ ahp->ah_cal_list_curr = NULL;
+ return false;
+ }
+
+ ath9k_hw_per_calibration(ah, &ichan, ahp->ah_rxchainmask,
+ currCal, &isCalDone);
+ if (!isCalDone) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: Not able to run Init Cal %d.\n",
+ __func__, calData->calType);
+ }
+ if (currCal->calNext) {
+ currCal = currCal->calNext;
+ calData = currCal->calData;
+ }
+ }
+
+ ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;
+ return true;
+}
+
+static inline bool
+ath9k_hw_channel_change(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ enum ath9k_ht_macmode macmode)
+{
+ u32 synthDelay, qnum;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
+ if (ath9k_hw_numtxpending(ah, qnum)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "%s: Transmit frames pending on queue %d\n",
+ __func__, qnum);
+ return false;
+ }
+ }
+
+ REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
+ if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
+ AR_PHY_RFBUS_GRANT_EN)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
+ "%s: Could not kill baseband RX\n", __func__);
+ return false;
+ }
+
+ ath9k_hw_set_regs(ah, chan, macmode);
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "%s: failed to set channel\n", __func__);
+ return false;
+ }
+ } else {
+ if (!(ath9k_hw_set_channel(ah, chan))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "%s: failed to set channel\n", __func__);
+ return false;
+ }
+ }
+
+ if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
+ ath9k_regd_get_ctl(ah, chan),
+ ath9k_regd_get_antenna_allowed(ah, chan),
+ chan->maxRegTxPower * 2,
+ min((u32) MAX_RATE_POWER,
+ (u32) ah->ah_powerLimit)) != 0) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "%s: error init'ing transmit power\n", __func__);
+ return false;
+ }
+
+ synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+ if (IS_CHAN_CCK(chan))
+ synthDelay = (4 * synthDelay) / 22;
+ else
+ synthDelay /= 10;
+
+ udelay(synthDelay + BASE_ACTIVATE_DELAY);
+
+ REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
+
+ if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
+ ath9k_hw_set_delta_slope(ah, chan);
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ath9k_hw_9280_spur_mitigate(ah, chan);
+ else
+ ath9k_hw_spur_mitigate(ah, chan);
+
+ if (!chan->oneTimeCalsDone)
+ chan->oneTimeCalsDone = true;
+
+ return true;
+}
+
+static bool ath9k_hw_chip_reset(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
+ return false;
+
+ if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+ return false;
+
+ ahp->ah_chipFullSleep = false;
+
+ ath9k_hw_init_pll(ah, chan);
+
+ ath9k_hw_set_rfmode(ah, chan);
+
+ return true;
+}
+
+static inline void ath9k_hw_set_dma(struct ath_hal *ah)
+{
+ u32 regval;
+
+ regval = REG_READ(ah, AR_AHB_MODE);
+ REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
+
+ regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
+ REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
+
+ REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel);
+
+ regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
+ REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
+
+ REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
+
+ if (AR_SREV_9285(ah)) {
+ REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
+ AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
+ } else {
+ REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
+ AR_PCU_TXBUF_CTRL_USABLE_SIZE);
+ }
+}
+
+bool ath9k_hw_stopdmarecv(struct ath_hal *ah)
+{
+ REG_WRITE(ah, AR_CR, AR_CR_RXD);
+ if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "%s: dma failed to stop in 10ms\n"
+ "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
+ __func__,
+ REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void ath9k_hw_startpcureceive(struct ath_hal *ah)
+{
+ REG_CLR_BIT(ah, AR_DIAG_SW,
+ (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+ ath9k_enable_mib_counters(ah);
+
+ ath9k_ani_reset(ah);
+}
+
+void ath9k_hw_stoppcurecv(struct ath_hal *ah)
+{
+ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
+
+ ath9k_hw_disable_mib_counters(ah);
+}
+
+static bool ath9k_hw_iscal_supported(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ enum hal_cal_types calType)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ bool retval = false;
+
+ switch (calType & ahp->ah_suppCals) {
+ case IQ_MISMATCH_CAL:
+ if (!IS_CHAN_B(chan))
+ retval = true;
+ break;
+ case ADC_GAIN_CAL:
+ case ADC_DC_CAL:
+ if (!IS_CHAN_B(chan)
+ && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
+ retval = true;
+ break;
+ }
+
+ return retval;
+}
+
+static inline bool ath9k_hw_init_cal(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *ichan =
+ ath9k_regd_check_channel(ah, chan);
+
+ REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+ REG_READ(ah, AR_PHY_AGC_CONTROL) |
+ AR_PHY_AGC_CONTROL_CAL);
+
+ if (!ath9k_hw_wait
+ (ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: offset calibration failed to complete in 1ms; "
+ "noisy environment?\n", __func__);
+ return false;
+ }
+
+ REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+ REG_READ(ah, AR_PHY_AGC_CONTROL) |
+ AR_PHY_AGC_CONTROL_NF);
+
+ ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr =
+ NULL;
+
+ if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
+ if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
+ INIT_CAL(&ahp->ah_adcGainCalData);
+ INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: enabling ADC Gain Calibration.\n",
+ __func__);
+ }
+ if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
+ INIT_CAL(&ahp->ah_adcDcCalData);
+ INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: enabling ADC DC Calibration.\n",
+ __func__);
+ }
+ if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
+ INIT_CAL(&ahp->ah_iqCalData);
+ INSERT_CAL(ahp, &ahp->ah_iqCalData);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: enabling IQ Calibration.\n",
+ __func__);
+ }
+
+ ahp->ah_cal_list_curr = ahp->ah_cal_list;
+
+ if (ahp->ah_cal_list_curr)
+ ath9k_hw_reset_calibration(ah,
+ ahp->ah_cal_list_curr);
+ }
+
+ ichan->CalValid = 0;
+
+ return true;
+}
+
+
+bool ath9k_hw_reset(struct ath_hal *ah, enum ath9k_opmode opmode,
+ struct ath9k_channel *chan,
+ enum ath9k_ht_macmode macmode,
+ u8 txchainmask, u8 rxchainmask,
+ enum ath9k_ht_extprotspacing extprotspacing,
+ bool bChannelChange,
+ int *status)
+{
+#define FAIL(_code) do { ecode = _code; goto bad; } while (0)
+ u32 saveLedState;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *curchan = ah->ah_curchan;
+ u32 saveDefAntenna;
+ u32 macStaId1;
+ int ecode;
+ int i, rx_chainmask;
+
+ ahp->ah_extprotspacing = extprotspacing;
+ ahp->ah_txchainmask = txchainmask;
+ ahp->ah_rxchainmask = rxchainmask;
+
+ if (AR_SREV_9280(ah)) {
+ ahp->ah_txchainmask &= 0x3;
+ ahp->ah_rxchainmask &= 0x3;
+ }
+
+ if (ath9k_hw_check_chan(ah, chan) == NULL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "%s: invalid channel %u/0x%x; no mapping\n",
+ __func__, chan->channel, chan->channelFlags);
+ FAIL(-EINVAL);
+ }
+
+ if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+ return false;
+
+ if (curchan)
+ ath9k_hw_getnf(ah, curchan);
+
+ if (bChannelChange &&
+ (ahp->ah_chipFullSleep != true) &&
+ (ah->ah_curchan != NULL) &&
+ (chan->channel != ah->ah_curchan->channel) &&
+ ((chan->channelFlags & CHANNEL_ALL) ==
+ (ah->ah_curchan->channelFlags & CHANNEL_ALL)) &&
+ (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) &&
+ !IS_CHAN_A_5MHZ_SPACED(ah->
+ ah_curchan)))) {
+
+ if (ath9k_hw_channel_change(ah, chan, macmode)) {
+ ath9k_hw_loadnf(ah, ah->ah_curchan);
+ ath9k_hw_start_nfcal(ah);
+ return true;
+ }
+ }
+
+ saveDefAntenna = REG_READ(ah, AR_DEF_ANTENNA);
+ if (saveDefAntenna == 0)
+ saveDefAntenna = 1;
+
+ macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;
+
+ saveLedState = REG_READ(ah, AR_CFG_LED) &
+ (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
+ AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW);
+
+ ath9k_hw_mark_phy_inactive(ah);
+
+ if (!ath9k_hw_chip_reset(ah, chan)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: chip reset failed\n",
+ __func__);
+ FAIL(-EIO);
+ }
+
+ if (AR_SREV_9280(ah)) {
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ AR_GPIO_JTAG_DISABLE);
+
+ if (test_bit(ATH9K_MODE_11A, ah->ah_caps.wireless_modes)) {
+ if (IS_CHAN_5GHZ(chan))
+ ath9k_hw_set_gpio(ah, 9, 0);
+ else
+ ath9k_hw_set_gpio(ah, 9, 1);
+ }
+ ath9k_hw_cfg_output(ah, 9, ATH9K_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ }
+
+ ecode = ath9k_hw_process_ini(ah, chan, macmode);
+ if (ecode != 0)
+ goto bad;
+
+ if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
+ ath9k_hw_set_delta_slope(ah, chan);
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ath9k_hw_9280_spur_mitigate(ah, chan);
+ else
+ ath9k_hw_spur_mitigate(ah, chan);
+
+ if (!ath9k_hw_eeprom_set_board_values(ah, chan)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+ "%s: error setting board options\n", __func__);
+ FAIL(-EIO);
+ }
+
+ ath9k_hw_decrease_chain_power(ah, chan);
+
+ REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(ahp->ah_macaddr));
+ REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(ahp->ah_macaddr + 4)
+ | macStaId1
+ | AR_STA_ID1_RTS_USE_DEF
+ | (ah->ah_config.
+ ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
+ | ahp->ah_staId1Defaults);
+ ath9k_hw_set_operating_mode(ah, opmode);
+
+ REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
+ REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
+
+ REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
+
+ REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
+ REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
+ ((ahp->ah_assocId & 0x3fff) << AR_BSS_ID1_AID_S));
+
+ REG_WRITE(ah, AR_ISR, ~0);
+
+ REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
+
+ if (AR_SREV_9280_10_OR_LATER(ah)) {
+ if (!(ath9k_hw_ar9280_set_channel(ah, chan)))
+ FAIL(-EIO);
+ } else {
+ if (!(ath9k_hw_set_channel(ah, chan)))
+ FAIL(-EIO);
+ }
+
+ for (i = 0; i < AR_NUM_DCU; i++)
+ REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
+
+ ahp->ah_intrTxqs = 0;
+ for (i = 0; i < ah->ah_caps.total_queues; i++)
+ ath9k_hw_resettxqueue(ah, i);
+
+ ath9k_hw_init_interrupt_masks(ah, opmode);
+ ath9k_hw_init_qos(ah);
+
+ ath9k_hw_init_user_settings(ah);
+
+ ah->ah_opmode = opmode;
+
+ REG_WRITE(ah, AR_STA_ID1,
+ REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
+
+ ath9k_hw_set_dma(ah);
+
+ REG_WRITE(ah, AR_OBS, 8);
+
+ if (ahp->ah_intrMitigation) {
+
+ REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
+ REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
+ }
+
+ ath9k_hw_init_bb(ah, chan);
+
+ if (!ath9k_hw_init_cal(ah, chan))
+ FAIL(-ENODEV);
+
+ rx_chainmask = ahp->ah_rxchainmask;
+ if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
+ REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
+ REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
+ }
+
+ REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ);
+
+ if (AR_SREV_9100(ah)) {
+ u32 mask;
+ mask = REG_READ(ah, AR_CFG);
+ if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "%s CFG Byte Swap Set 0x%x\n", __func__,
+ mask);
+ } else {
+ mask =
+ INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
+ REG_WRITE(ah, AR_CFG, mask);
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "%s Setting CFG 0x%x\n", __func__,
+ REG_READ(ah, AR_CFG));
+ }
+ } else {
+#ifdef __BIG_ENDIAN
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+#endif
+ }
+
+ return true;
+bad:
+ if (status)
+ *status = ecode;
+ return false;
+#undef FAIL
+}
+
+bool ath9k_hw_phy_disable(struct ath_hal *ah)
+{
+ return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM);
+}
+
+bool ath9k_hw_disable(struct ath_hal *ah)
+{
+ if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
+ return false;
+
+ return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
+}
+
+bool
+ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan,
+ u8 rxchainmask, bool longcal,
+ bool *isCalDone)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+ struct ath9k_channel *ichan =
+ ath9k_regd_check_channel(ah, chan);
+
+ *isCalDone = true;
+
+ if (ichan == NULL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "%s: invalid channel %u/0x%x; no mapping\n",
+ __func__, chan->channel, chan->channelFlags);
+ return false;
+ }
+
+ if (currCal &&
+ (currCal->calState == CAL_RUNNING ||
+ currCal->calState == CAL_WAITING)) {
+ ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal,
+ isCalDone);
+ if (*isCalDone) {
+ ahp->ah_cal_list_curr = currCal = currCal->calNext;
+
+ if (currCal->calState == CAL_WAITING) {
+ *isCalDone = false;
+ ath9k_hw_reset_calibration(ah, currCal);
+ }
+ }
+ }
+
+ if (longcal) {
+ ath9k_hw_getnf(ah, ichan);
+ ath9k_hw_loadnf(ah, ah->ah_curchan);
+ ath9k_hw_start_nfcal(ah);
+
+ if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) {
+
+ chan->channelFlags |= CHANNEL_CW_INT;
+ ichan->channelFlags &= ~CHANNEL_CW_INT;
+ }
+ }
+
+ return true;
+}
+
+static void ath9k_hw_iqcal_collect(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ ahp->ah_totalPowerMeasI[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+ ahp->ah_totalPowerMeasQ[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+ ahp->ah_totalIqCorrMeas[i] +=
+ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+ ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i],
+ ahp->ah_totalPowerMeasQ[i],
+ ahp->ah_totalIqCorrMeas[i]);
+ }
+}
+
+static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ ahp->ah_totalAdcIOddPhase[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+ ahp->ah_totalAdcIEvenPhase[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+ ahp->ah_totalAdcQOddPhase[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+ ahp->ah_totalAdcQEvenPhase[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+ "oddq=0x%08x; evenq=0x%08x;\n",
+ ahp->ah_CalSamples, i,
+ ahp->ah_totalAdcIOddPhase[i],
+ ahp->ah_totalAdcIEvenPhase[i],
+ ahp->ah_totalAdcQOddPhase[i],
+ ahp->ah_totalAdcQEvenPhase[i]);
+ }
+}
+
+static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int i;
+
+ for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ ahp->ah_totalAdcDcOffsetIOddPhase[i] +=
+ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+ ahp->ah_totalAdcDcOffsetIEvenPhase[i] +=
+ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+ ahp->ah_totalAdcDcOffsetQOddPhase[i] +=
+ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+ ahp->ah_totalAdcDcOffsetQEvenPhase[i] +=
+ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+ "oddq=0x%08x; evenq=0x%08x;\n",
+ ahp->ah_CalSamples, i,
+ ahp->ah_totalAdcDcOffsetIOddPhase[i],
+ ahp->ah_totalAdcDcOffsetIEvenPhase[i],
+ ahp->ah_totalAdcDcOffsetQOddPhase[i],
+ ahp->ah_totalAdcDcOffsetQEvenPhase[i]);
+ }
+}
+
+static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 powerMeasQ, powerMeasI, iqCorrMeas;
+ u32 qCoffDenom, iCoffDenom;
+ int32_t qCoff, iCoff;
+ int iqCorrNeg, i;
+
+ for (i = 0; i < numChains; i++) {
+ powerMeasI = ahp->ah_totalPowerMeasI[i];
+ powerMeasQ = ahp->ah_totalPowerMeasQ[i];
+ iqCorrMeas = ahp->ah_totalIqCorrMeas[i];
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Starting IQ Cal and Correction for Chain %d\n",
+ i);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Orignal: Chn %diq_corr_meas = 0x%08x\n",
+ i, ahp->ah_totalIqCorrMeas[i]);
+
+ iqCorrNeg = 0;
+
+
+ if (iqCorrMeas > 0x80000000) {
+ iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
+ iqCorrNeg = 1;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
+ iqCorrNeg);
+
+ iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
+ qCoffDenom = powerMeasQ / 64;
+
+ if (powerMeasQ != 0) {
+
+ iCoff = iqCorrMeas / iCoffDenom;
+ qCoff = powerMeasI / qCoffDenom - 64;
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d iCoff = 0x%08x\n", i, iCoff);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d qCoff = 0x%08x\n", i, qCoff);
+
+
+ iCoff = iCoff & 0x3f;
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
+ if (iqCorrNeg == 0x0)
+ iCoff = 0x40 - iCoff;
+
+ if (qCoff > 15)
+ qCoff = 15;
+ else if (qCoff <= -16)
+ qCoff = 16;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
+ i, iCoff, qCoff);
+
+ REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
+ iCoff);
+ REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+ AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
+ qCoff);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "IQ Cal and Correction done for Chain %d\n",
+ i);
+ }
+ }
+
+ REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+ AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
+}
+
+static void
+ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset,
+ qEvenMeasOffset;
+ u32 qGainMismatch, iGainMismatch, val, i;
+
+ for (i = 0; i < numChains; i++) {
+ iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i];
+ iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i];
+ qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i];
+ qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i];
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Starting ADC Gain Cal for Chain %d\n", i);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
+ iOddMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_i = 0x%08x\n", i,
+ iEvenMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
+ qOddMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_q = 0x%08x\n", i,
+ qEvenMeasOffset);
+
+ if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
+ iGainMismatch =
+ ((iEvenMeasOffset * 32) /
+ iOddMeasOffset) & 0x3f;
+ qGainMismatch =
+ ((qOddMeasOffset * 32) /
+ qEvenMeasOffset) & 0x3f;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d gain_mismatch_i = 0x%08x\n", i,
+ iGainMismatch);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d gain_mismatch_q = 0x%08x\n", i,
+ qGainMismatch);
+
+ val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+ val &= 0xfffff000;
+ val |= (qGainMismatch) | (iGainMismatch << 6);
+ REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "ADC Gain Cal done for Chain %d\n", i);
+ }
+ }
+
+ REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+ REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+ AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
+}
+
+static void
+ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 iOddMeasOffset, iEvenMeasOffset, val, i;
+ int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
+ const struct hal_percal_data *calData =
+ ahp->ah_cal_list_curr->calData;
+ u32 numSamples =
+ (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
+
+ for (i = 0; i < numChains; i++) {
+ iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i];
+ iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i];
+ qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i];
+ qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i];
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Starting ADC DC Offset Cal for Chain %d\n", i);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_i = %d\n", i,
+ iOddMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_i = %d\n", i,
+ iEvenMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_odd_q = %d\n", i,
+ qOddMeasOffset);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d pwr_meas_even_q = %d\n", i,
+ qEvenMeasOffset);
+
+ iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
+ numSamples) & 0x1ff;
+ qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
+ numSamples) & 0x1ff;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
+ iDcMismatch);
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
+ qDcMismatch);
+
+ val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+ val &= 0xc0000fff;
+ val |= (qDcMismatch << 12) | (iDcMismatch << 21);
+ REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "ADC DC Offset Cal done for Chain %d\n", i);
+ }
+
+ REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+ REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+ AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
+}
+
+bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *chan = ah->ah_curchan;
+
+ ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER);
+
+ if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan,
+ ath9k_regd_get_ctl(ah, chan),
+ ath9k_regd_get_antenna_allowed(ah,
+ chan),
+ chan->maxRegTxPower * 2,
+ min((u32) MAX_RATE_POWER,
+ (u32) ah->ah_powerLimit)) != 0)
+ return false;
+
+ return true;
+}
+
+void
+ath9k_hw_get_channel_centers(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ struct chan_centers *centers)
+{
+ int8_t extoff;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (!IS_CHAN_HT40(chan)) {
+ centers->ctl_center = centers->ext_center =
+ centers->synth_center = chan->channel;
+ return;
+ }
+
+ if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+ (chan->chanmode == CHANNEL_G_HT40PLUS)) {
+ centers->synth_center =
+ chan->channel + HT40_CHANNEL_CENTER_SHIFT;
+ extoff = 1;
+ } else {
+ centers->synth_center =
+ chan->channel - HT40_CHANNEL_CENTER_SHIFT;
+ extoff = -1;
+ }
+
+ centers->ctl_center = centers->synth_center - (extoff *
+ HT40_CHANNEL_CENTER_SHIFT);
+ centers->ext_center = centers->synth_center + (extoff *
+ ((ahp->
+ ah_extprotspacing
+ ==
+ ATH9K_HT_EXTPROTSPACING_20)
+ ?
+ HT40_CHANNEL_CENTER_SHIFT
+ : 15));
+
+}
+
+void
+ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan,
+ bool *isCalDone)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *ichan =
+ ath9k_regd_check_channel(ah, chan);
+ struct hal_cal_list *currCal = ahp->ah_cal_list_curr;
+
+ *isCalDone = true;
+
+ if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
+ return;
+
+ if (currCal == NULL)
+ return;
+
+ if (ichan == NULL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: invalid channel %u/0x%x; no mapping\n",
+ __func__, chan->channel, chan->channelFlags);
+ return;
+ }
+
+
+ if (currCal->calState != CAL_DONE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: Calibration state incorrect, %d\n",
+ __func__, currCal->calState);
+ return;
+ }
+
+
+ if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType))
+ return;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+ "%s: Resetting Cal %d state for channel %u/0x%x\n",
+ __func__, currCal->calData->calType, chan->channel,
+ chan->channelFlags);
+
+ ichan->CalValid &= ~currCal->calData->calType;
+ currCal->calState = CAL_WAITING;
+
+ *isCalDone = false;
+}
+
+void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ memcpy(mac, ahp->ah_macaddr, ETH_ALEN);
+}
+
+bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ memcpy(ahp->ah_macaddr, mac, ETH_ALEN);
+ return true;
+}
+
+void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ memcpy(mask, ahp->ah_bssidmask, ETH_ALEN);
+}
+
+bool
+ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ memcpy(ahp->ah_bssidmask, mask, ETH_ALEN);
+
+ REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask));
+ REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4));
+
+ return true;
+}
+
+#ifdef CONFIG_ATH9K_RFKILL
+static void ath9k_enable_rfkill(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
+
+ REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+ AR_GPIO_INPUT_MUX2_RFSILENT);
+
+ ath9k_hw_cfg_gpio_input(ah, ahp->ah_gpioSelect);
+ REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
+
+ if (ahp->ah_gpioBit == ath9k_hw_gpio_get(ah, ahp->ah_gpioSelect)) {
+
+ ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect,
+ !ahp->ah_gpioBit);
+ } else {
+ ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect,
+ ahp->ah_gpioBit);
+ }
+}
+#endif
+
+void
+ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
+ u16 assocId)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ memcpy(ahp->ah_bssid, bssid, ETH_ALEN);
+ ahp->ah_assocId = assocId;
+
+ REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid));
+ REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) |
+ ((assocId & 0x3fff) << AR_BSS_ID1_AID_S));
+}
+
+u64 ath9k_hw_gettsf64(struct ath_hal *ah)
+{
+ u64 tsf;
+
+ tsf = REG_READ(ah, AR_TSF_U32);
+ tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32);
+ return tsf;
+}
+
+void ath9k_hw_reset_tsf(struct ath_hal *ah)
+{
+ int count;
+
+ count = 0;
+ while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
+ count++;
+ if (count > 10) {
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "%s: AR_SLP32_TSF_WRITE_STATUS limit exceeded\n",
+ __func__);
+ break;
+ }
+ udelay(10);
+ }
+ REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
+}
+
+u32 ath9k_hw_getdefantenna(struct ath_hal *ah)
+{
+ return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
+}
+
+void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna)
+{
+ REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7));
+}
+
+bool
+ath9k_hw_setantennaswitch(struct ath_hal *ah,
+ enum ath9k_ant_setting settings,
+ struct ath9k_channel *chan,
+ u8 *tx_chainmask,
+ u8 *rx_chainmask,
+ u8 *antenna_cfgd)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ static u8 tx_chainmask_cfg, rx_chainmask_cfg;
+
+ if (AR_SREV_9280(ah)) {
+ if (!tx_chainmask_cfg) {
+
+ tx_chainmask_cfg = *tx_chainmask;
+ rx_chainmask_cfg = *rx_chainmask;
+ }
+
+ switch (settings) {
+ case ATH9K_ANT_FIXED_A:
+ *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
+ *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK;
+ *antenna_cfgd = true;
+ break;
+ case ATH9K_ANT_FIXED_B:
+ if (ah->ah_caps.tx_chainmask >
+ ATH9K_ANTENNA1_CHAINMASK) {
+ *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
+ }
+ *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK;
+ *antenna_cfgd = true;
+ break;
+ case ATH9K_ANT_VARIABLE:
+ *tx_chainmask = tx_chainmask_cfg;
+ *rx_chainmask = rx_chainmask_cfg;
+ *antenna_cfgd = true;
+ break;
+ default:
+ break;
+ }
+ } else {
+ ahp->ah_diversityControl = settings;
+ }
+
+ return true;
+}
+
+void ath9k_hw_setopmode(struct ath_hal *ah)
+{
+ ath9k_hw_set_operating_mode(ah, ah->ah_opmode);
+}
+
+bool
+ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type,
+ u32 capability, u32 *result)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+ switch (type) {
+ case ATH9K_CAP_CIPHER:
+ switch (capability) {
+ case ATH9K_CIPHER_AES_CCM:
+ case ATH9K_CIPHER_AES_OCB:
+ case ATH9K_CIPHER_TKIP:
+ case ATH9K_CIPHER_WEP:
+ case ATH9K_CIPHER_MIC:
+ case ATH9K_CIPHER_CLR:
+ return true;
+ default:
+ return false;
+ }
+ case ATH9K_CAP_TKIP_MIC:
+ switch (capability) {
+ case 0:
+ return true;
+ case 1:
+ return (ahp->ah_staId1Defaults &
+ AR_STA_ID1_CRPT_MIC_ENABLE) ? true :
+ false;
+ }
+ case ATH9K_CAP_TKIP_SPLIT:
+ return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ?
+ false : true;
+ case ATH9K_CAP_WME_TKIPMIC:
+ return 0;
+ case ATH9K_CAP_PHYCOUNTERS:
+ return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO;
+ case ATH9K_CAP_DIVERSITY:
+ return (REG_READ(ah, AR_PHY_CCK_DETECT) &
+ AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
+ true : false;
+ case ATH9K_CAP_PHYDIAG:
+ return true;
+ case ATH9K_CAP_MCAST_KEYSRCH:
+ switch (capability) {
+ case 0:
+ return true;
+ case 1:
+ if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) {
+ return false;
+ } else {
+ return (ahp->ah_staId1Defaults &
+ AR_STA_ID1_MCAST_KSRCH) ? true :
+ false;
+ }
+ }
+ return false;
+ case ATH9K_CAP_TSF_ADJUST:
+ return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ?
+ true : false;
+ case ATH9K_CAP_RFSILENT:
+ if (capability == 3)
+ return false;
+ case ATH9K_CAP_ANT_CFG_2GHZ:
+ *result = pCap->num_antcfg_2ghz;
+ return true;
+ case ATH9K_CAP_ANT_CFG_5GHZ:
+ *result = pCap->num_antcfg_5ghz;
+ return true;
+ case ATH9K_CAP_TXPOW:
+ switch (capability) {
+ case 0:
+ return 0;
+ case 1:
+ *result = ah->ah_powerLimit;
+ return 0;
+ case 2:
+ *result = ah->ah_maxPowerLevel;
+ return 0;
+ case 3:
+ *result = ah->ah_tpScale;
+ return 0;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+int
+ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_channel *chan = ah->ah_curchan;
+ const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ u16 ant_config;
+ u32 halNumAntConfig;
+
+ halNumAntConfig =
+ IS_CHAN_2GHZ(chan) ? pCap->num_antcfg_2ghz : pCap->
+ num_antcfg_5ghz;
+
+ if (cfg < halNumAntConfig) {
+ if (!ath9k_hw_get_eeprom_antenna_cfg(ahp, chan,
+ cfg, &ant_config)) {
+ REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+bool ath9k_hw_intrpend(struct ath_hal *ah)
+{
+ u32 host_isr;
+
+ if (AR_SREV_9100(ah))
+ return true;
+
+ host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
+ if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS))
+ return true;
+
+ host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE);
+ if ((host_isr & AR_INTR_SYNC_DEFAULT)
+ && (host_isr != AR_INTR_SPURIOUS))
+ return true;
+
+ return false;
+}
+
+bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked)
+{
+ u32 isr = 0;
+ u32 mask2 = 0;
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ u32 sync_cause = 0;
+ bool fatal_int = false;
+
+ if (!AR_SREV_9100(ah)) {
+ if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
+ if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
+ == AR_RTC_STATUS_ON) {
+ isr = REG_READ(ah, AR_ISR);
+ }
+ }
+
+ sync_cause =
+ REG_READ(ah,
+ AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT;
+
+ *masked = 0;
+
+ if (!isr && !sync_cause)
+ return false;
+ } else {
+ *masked = 0;
+ isr = REG_READ(ah, AR_ISR);
+ }
+
+ if (isr) {
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (isr & AR_ISR_BCNMISC) {
+ u32 isr2;
+ isr2 = REG_READ(ah, AR_ISR_S2);
+ if (isr2 & AR_ISR_S2_TIM)
+ mask2 |= ATH9K_INT_TIM;
+ if (isr2 & AR_ISR_S2_DTIM)
+ mask2 |= ATH9K_INT_DTIM;
+ if (isr2 & AR_ISR_S2_DTIMSYNC)
+ mask2 |= ATH9K_INT_DTIMSYNC;
+ if (isr2 & (AR_ISR_S2_CABEND))
+ mask2 |= ATH9K_INT_CABEND;
+ if (isr2 & AR_ISR_S2_GTT)
+ mask2 |= ATH9K_INT_GTT;
+ if (isr2 & AR_ISR_S2_CST)
+ mask2 |= ATH9K_INT_CST;
+ }
+
+ isr = REG_READ(ah, AR_ISR_RAC);
+ if (isr == 0xffffffff) {
+ *masked = 0;
+ return false;
+ }
+
+ *masked = isr & ATH9K_INT_COMMON;
+
+ if (ahp->ah_intrMitigation) {
+
+ if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
+ *masked |= ATH9K_INT_RX;
+ }
+
+ if (isr & (AR_ISR_RXOK | AR_ISR_RXERR))
+ *masked |= ATH9K_INT_RX;
+ if (isr &
+ (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
+ AR_ISR_TXEOL)) {
+ u32 s0_s, s1_s;
+
+ *masked |= ATH9K_INT_TX;
+
+ s0_s = REG_READ(ah, AR_ISR_S0_S);
+ ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
+ ahp->ah_intrTxqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
+
+ s1_s = REG_READ(ah, AR_ISR_S1_S);
+ ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
+ ahp->ah_intrTxqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
+ }
+
+ if (isr & AR_ISR_RXORN) {
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
+ "%s: receive FIFO overrun interrupt\n",
+ __func__);
+ }
+
+ if (!AR_SREV_9100(ah)) {
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+ u32 isr5 = REG_READ(ah, AR_ISR_S5_S);
+ if (isr5 & AR_ISR_S5_TIM_TIMER)
+ *masked |= ATH9K_INT_TIM_TIMER;
+ }
+ }
+
+ *masked |= mask2;
+ }
+ if (AR_SREV_9100(ah))
+ return true;
+ if (sync_cause) {
+ fatal_int =
+ (sync_cause &
+ (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))
+ ? true : false;
+
+ if (fatal_int) {
+ if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ "%s: received PCI FATAL interrupt\n",
+ __func__);
+ }
+ if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ "%s: received PCI PERR interrupt\n",
+ __func__);
+ }
+ }
+ if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
+ "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n",
+ __func__);
+ REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
+ REG_WRITE(ah, AR_RC, 0);
+ *masked |= ATH9K_INT_FATAL;
+ }
+ if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) {
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
+ "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n",
+ __func__);
+ }
+
+ REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
+ (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
+ }
+ return true;
+}
+
+enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah)
+{
+ return AH5416(ah)->ah_maskReg;
+}
+
+enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 omask = ahp->ah_maskReg;
+ u32 mask, mask2;
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: 0x%x => 0x%x\n", __func__,
+ omask, ints);
+
+ if (omask & ATH9K_INT_GLOBAL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: disable IER\n",
+ __func__);
+ REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
+ (void) REG_READ(ah, AR_IER);
+ if (!AR_SREV_9100(ah)) {
+ REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
+ (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
+
+ REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
+ (void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
+ }
+ }
+
+ mask = ints & ATH9K_INT_COMMON;
+ mask2 = 0;
+
+ if (ints & ATH9K_INT_TX) {
+ if (ahp->ah_txOkInterruptMask)
+ mask |= AR_IMR_TXOK;
+ if (ahp->ah_txDescInterruptMask)
+ mask |= AR_IMR_TXDESC;
+ if (ahp->ah_txErrInterruptMask)
+ mask |= AR_IMR_TXERR;
+ if (ahp->ah_txEolInterruptMask)
+ mask |= AR_IMR_TXEOL;
+ }
+ if (ints & ATH9K_INT_RX) {
+ mask |= AR_IMR_RXERR;
+ if (ahp->ah_intrMitigation)
+ mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
+ else
+ mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+ mask |= AR_IMR_GENTMR;
+ }
+
+ if (ints & (ATH9K_INT_BMISC)) {
+ mask |= AR_IMR_BCNMISC;
+ if (ints & ATH9K_INT_TIM)
+ mask2 |= AR_IMR_S2_TIM;
+ if (ints & ATH9K_INT_DTIM)
+ mask2 |= AR_IMR_S2_DTIM;
+ if (ints & ATH9K_INT_DTIMSYNC)
+ mask2 |= AR_IMR_S2_DTIMSYNC;
+ if (ints & ATH9K_INT_CABEND)
+ mask2 |= (AR_IMR_S2_CABEND);
+ }
+
+ if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) {
+ mask |= AR_IMR_BCNMISC;
+ if (ints & ATH9K_INT_GTT)
+ mask2 |= AR_IMR_S2_GTT;
+ if (ints & ATH9K_INT_CST)
+ mask2 |= AR_IMR_S2_CST;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: new IMR 0x%x\n", __func__,
+ mask);
+ REG_WRITE(ah, AR_IMR, mask);
+ mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM |
+ AR_IMR_S2_DTIM |
+ AR_IMR_S2_DTIMSYNC |
+ AR_IMR_S2_CABEND |
+ AR_IMR_S2_CABTO |
+ AR_IMR_S2_TSFOOR |
+ AR_IMR_S2_GTT | AR_IMR_S2_CST);
+ REG_WRITE(ah, AR_IMR_S2, mask | mask2);
+ ahp->ah_maskReg = ints;
+
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+ if (ints & ATH9K_INT_TIM_TIMER)
+ REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
+ else
+ REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
+ }
+
+ if (ints & ATH9K_INT_GLOBAL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: enable IER\n",
+ __func__);
+ REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
+ if (!AR_SREV_9100(ah)) {
+ REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
+ AR_INTR_MAC_IRQ);
+ REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
+
+
+ REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
+ AR_INTR_SYNC_DEFAULT);
+ REG_WRITE(ah, AR_INTR_SYNC_MASK,
+ AR_INTR_SYNC_DEFAULT);
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
+ REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
+ }
+
+ return omask;
+}
+
+void
+ath9k_hw_beaconinit(struct ath_hal *ah,
+ u32 next_beacon, u32 beacon_period)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ int flags = 0;
+
+ ahp->ah_beaconInterval = beacon_period;
+
+ switch (ah->ah_opmode) {
+ case ATH9K_M_STA:
+ case ATH9K_M_MONITOR:
+ REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
+ REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff);
+ REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff);
+ flags |= AR_TBTT_TIMER_EN;
+ break;
+ case ATH9K_M_IBSS:
+ REG_SET_BIT(ah, AR_TXCFG,
+ AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
+ REG_WRITE(ah, AR_NEXT_NDP_TIMER,
+ TU_TO_USEC(next_beacon +
+ (ahp->ah_atimWindow ? ahp->
+ ah_atimWindow : 1)));
+ flags |= AR_NDP_TIMER_EN;
+ case ATH9K_M_HOSTAP:
+ REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
+ REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
+ TU_TO_USEC(next_beacon -
+ ah->ah_config.
+ dma_beacon_response_time));
+ REG_WRITE(ah, AR_NEXT_SWBA,
+ TU_TO_USEC(next_beacon -
+ ah->ah_config.
+ sw_beacon_response_time));
+ flags |=
+ AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
+ break;
+ }
+
+ REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period));
+ REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period));
+ REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period));
+ REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
+
+ beacon_period &= ~ATH9K_BEACON_ENA;
+ if (beacon_period & ATH9K_BEACON_RESET_TSF) {
+ beacon_period &= ~ATH9K_BEACON_RESET_TSF;
+ ath9k_hw_reset_tsf(ah);
+ }
+
+ REG_SET_BIT(ah, AR_TIMER_MODE, flags);
+}
+
+void
+ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah,
+ const struct ath9k_beacon_state *bs)
+{
+ u32 nextTbtt, beaconintval, dtimperiod, beacontimeout;
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+ REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
+
+ REG_WRITE(ah, AR_BEACON_PERIOD,
+ TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
+ REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
+ TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
+
+ REG_RMW_FIELD(ah, AR_RSSI_THR,
+ AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
+
+ beaconintval = bs->bs_intval & ATH9K_BEACON_PERIOD;
+
+ if (bs->bs_sleepduration > beaconintval)
+ beaconintval = bs->bs_sleepduration;
+
+ dtimperiod = bs->bs_dtimperiod;
+ if (bs->bs_sleepduration > dtimperiod)
+ dtimperiod = bs->bs_sleepduration;
+
+ if (beaconintval == dtimperiod)
+ nextTbtt = bs->bs_nextdtim;
+ else
+ nextTbtt = bs->bs_nexttbtt;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next DTIM %d\n", __func__,
+ bs->bs_nextdtim);
+ DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next beacon %d\n", __func__,
+ nextTbtt);
+ DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: beacon period %d\n", __func__,
+ beaconintval);
+ DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: DTIM period %d\n", __func__,
+ dtimperiod);
+
+ REG_WRITE(ah, AR_NEXT_DTIM,
+ TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
+ REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));
+
+ REG_WRITE(ah, AR_SLEEP1,
+ SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT)
+ | AR_SLEEP1_ASSUME_DTIM);
+
+ if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)
+ beacontimeout = (BEACON_TIMEOUT_VAL << 3);
+ else
+ beacontimeout = MIN_BEACON_TIMEOUT_VAL;
+
+ REG_WRITE(ah, AR_SLEEP2,
+ SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT));
+
+ REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
+ REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
+
+ REG_SET_BIT(ah, AR_TIMER_MODE,
+ AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
+ AR_DTIM_TIMER_EN);
+
+}
+
+bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry)
+{
+ if (entry < ah->ah_caps.keycache_size) {
+ u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));
+ if (val & AR_KEYTABLE_VALID)
+ return true;
+ }
+ return false;
+}
+
+bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry)
+{
+ u32 keyType;
+
+ if (entry >= ah->ah_caps.keycache_size) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "%s: entry %u out of range\n", __func__, entry);
+ return false;
+ }
+ keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
+
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR);
+ REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0);
+
+ if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
+ u16 micentry = entry + 64;
+
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+
+ }
+
+ if (ah->ah_curchan == NULL)
+ return true;
+
+ return true;
+}
+
+bool
+ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry,
+ const u8 *mac)
+{
+ u32 macHi, macLo;
+
+ if (entry >= ah->ah_caps.keycache_size) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "%s: entry %u out of range\n", __func__, entry);
+ return false;
+ }
+
+ if (mac != NULL) {
+ macHi = (mac[5] << 8) | mac[4];
+ macLo = (mac[3] << 24) | (mac[2] << 16)
+ | (mac[1] << 8) | mac[0];
+ macLo >>= 1;
+ macLo |= (macHi & 1) << 31;
+ macHi >>= 1;
+ } else {
+ macLo = macHi = 0;
+ }
+ REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
+ REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID);
+
+ return true;
+}
+
+bool
+ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry,
+ const struct ath9k_keyval *k,
+ const u8 *mac, int xorKey)
+{
+ const struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ u32 key0, key1, key2, key3, key4;
+ u32 keyType;
+ u32 xorMask = xorKey ?
+ (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8
+ | ATH9K_KEY_XOR) : 0;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (entry >= pCap->keycache_size) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "%s: entry %u out of range\n", __func__, entry);
+ return false;
+ }
+ switch (k->kv_type) {
+ case ATH9K_CIPHER_AES_OCB:
+ keyType = AR_KEYTABLE_TYPE_AES;
+ break;
+ case ATH9K_CIPHER_AES_CCM:
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "%s: AES-CCM not supported by "
+ "mac rev 0x%x\n", __func__,
+ ah->ah_macRev);
+ return false;
+ }
+ keyType = AR_KEYTABLE_TYPE_CCM;
+ break;
+ case ATH9K_CIPHER_TKIP:
+ keyType = AR_KEYTABLE_TYPE_TKIP;
+ if (ATH9K_IS_MIC_ENABLED(ah)
+ && entry + 64 >= pCap->keycache_size) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "%s: entry %u inappropriate for TKIP\n",
+ __func__, entry);
+ return false;
+ }
+ break;
+ case ATH9K_CIPHER_WEP:
+ if (k->kv_len < LEN_WEP40) {
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "%s: WEP key length %u too small\n",
+ __func__, k->kv_len);
+ return false;
+ }
+ if (k->kv_len <= LEN_WEP40)
+ keyType = AR_KEYTABLE_TYPE_40;
+ else if (k->kv_len <= LEN_WEP104)
+ keyType = AR_KEYTABLE_TYPE_104;
+ else
+ keyType = AR_KEYTABLE_TYPE_128;
+ break;
+ case ATH9K_CIPHER_CLR:
+ keyType = AR_KEYTABLE_TYPE_CLR;
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
+ "%s: cipher %u not supported\n", __func__,
+ k->kv_type);
+ return false;
+ }
+
+ key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask;
+ key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff;
+ key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask;
+ key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff;
+ key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask;
+ if (k->kv_len <= LEN_WEP104)
+ key4 &= 0xff;
+
+ if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
+ u16 micentry = entry + 64;
+
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+ (void) ath9k_hw_keysetmac(ah, entry, mac);
+
+ if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) {
+ u32 mic0, mic1, mic2, mic3, mic4;
+
+ mic0 = get_unaligned_le32(k->kv_mic + 0);
+ mic2 = get_unaligned_le32(k->kv_mic + 4);
+ mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
+ mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
+ mic4 = get_unaligned_le32(k->kv_txmic + 4);
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
+ AR_KEYTABLE_TYPE_CLR);
+
+ } else {
+ u32 mic0, mic2;
+
+ mic0 = get_unaligned_le32(k->kv_mic + 0);
+ mic2 = get_unaligned_le32(k->kv_mic + 4);
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
+ AR_KEYTABLE_TYPE_CLR);
+ }
+ REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+ } else {
+ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
+ REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
+ REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
+ REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+
+ (void) ath9k_hw_keysetmac(ah, entry, mac);
+ }
+
+ if (ah->ah_curchan == NULL)
+ return true;
+
+ return true;
+}
+
+bool
+ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 txcfg, curLevel, newLevel;
+ enum ath9k_int omask;
+
+ if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD)
+ return false;
+
+ omask = ath9k_hw_set_interrupts(ah,
+ ahp->ah_maskReg & ~ATH9K_INT_GLOBAL);
+
+ txcfg = REG_READ(ah, AR_TXCFG);
+ curLevel = MS(txcfg, AR_FTRIG);
+ newLevel = curLevel;
+ if (bIncTrigLevel) {
+ if (curLevel < MAX_TX_FIFO_THRESHOLD)
+ newLevel++;
+ } else if (curLevel > MIN_TX_FIFO_THRESHOLD)
+ newLevel--;
+ if (newLevel != curLevel)
+ REG_WRITE(ah, AR_TXCFG,
+ (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG));
+
+ ath9k_hw_set_interrupts(ah, omask);
+
+ ah->ah_txTrigLevel = newLevel;
+
+ return newLevel != curLevel;
+}
+
+bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q,
+ const struct ath9k_tx_queue_info *qinfo)
+{
+ u32 cw;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ struct ath9k_tx_queue_info *qi;
+
+ if (q >= pCap->total_queues) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+ __func__, q);
+ return false;
+ }
+
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
+ __func__);
+ return false;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi);
+
+ qi->tqi_ver = qinfo->tqi_ver;
+ qi->tqi_subtype = qinfo->tqi_subtype;
+ qi->tqi_qflags = qinfo->tqi_qflags;
+ qi->tqi_priority = qinfo->tqi_priority;
+ if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT)
+ qi->tqi_aifs = min(qinfo->tqi_aifs, 255U);
+ else
+ qi->tqi_aifs = INIT_AIFS;
+ if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) {
+ cw = min(qinfo->tqi_cwmin, 1024U);
+ qi->tqi_cwmin = 1;
+ while (qi->tqi_cwmin < cw)
+ qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1;
+ } else
+ qi->tqi_cwmin = qinfo->tqi_cwmin;
+ if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) {
+ cw = min(qinfo->tqi_cwmax, 1024U);
+ qi->tqi_cwmax = 1;
+ while (qi->tqi_cwmax < cw)
+ qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1;
+ } else
+ qi->tqi_cwmax = INIT_CWMAX;
+
+ if (qinfo->tqi_shretry != 0)
+ qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U);
+ else
+ qi->tqi_shretry = INIT_SH_RETRY;
+ if (qinfo->tqi_lgretry != 0)
+ qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U);
+ else
+ qi->tqi_lgretry = INIT_LG_RETRY;
+ qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod;
+ qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit;
+ qi->tqi_burstTime = qinfo->tqi_burstTime;
+ qi->tqi_readyTime = qinfo->tqi_readyTime;
+
+ switch (qinfo->tqi_subtype) {
+ case ATH9K_WME_UPSD:
+ if (qi->tqi_type == ATH9K_TX_QUEUE_DATA)
+ qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS;
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q,
+ struct ath9k_tx_queue_info *qinfo)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ struct ath9k_tx_queue_info *qi;
+
+ if (q >= pCap->total_queues) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+ __func__, q);
+ return false;
+ }
+
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n",
+ __func__);
+ return false;
+ }
+
+ qinfo->tqi_qflags = qi->tqi_qflags;
+ qinfo->tqi_ver = qi->tqi_ver;
+ qinfo->tqi_subtype = qi->tqi_subtype;
+ qinfo->tqi_qflags = qi->tqi_qflags;
+ qinfo->tqi_priority = qi->tqi_priority;
+ qinfo->tqi_aifs = qi->tqi_aifs;
+ qinfo->tqi_cwmin = qi->tqi_cwmin;
+ qinfo->tqi_cwmax = qi->tqi_cwmax;
+ qinfo->tqi_shretry = qi->tqi_shretry;
+ qinfo->tqi_lgretry = qi->tqi_lgretry;
+ qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod;
+ qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit;
+ qinfo->tqi_burstTime = qi->tqi_burstTime;
+ qinfo->tqi_readyTime = qi->tqi_readyTime;
+
+ return true;
+}
+
+int
+ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type,
+ const struct ath9k_tx_queue_info *qinfo)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_tx_queue_info *qi;
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ int q;
+
+ switch (type) {
+ case ATH9K_TX_QUEUE_BEACON:
+ q = pCap->total_queues - 1;
+ break;
+ case ATH9K_TX_QUEUE_CAB:
+ q = pCap->total_queues - 2;
+ break;
+ case ATH9K_TX_QUEUE_PSPOLL:
+ q = 1;
+ break;
+ case ATH9K_TX_QUEUE_UAPSD:
+ q = pCap->total_queues - 3;
+ break;
+ case ATH9K_TX_QUEUE_DATA:
+ for (q = 0; q < pCap->total_queues; q++)
+ if (ahp->ah_txq[q].tqi_type ==
+ ATH9K_TX_QUEUE_INACTIVE)
+ break;
+ if (q == pCap->total_queues) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "%s: no available tx queue\n", __func__);
+ return -1;
+ }
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: bad tx queue type %u\n",
+ __func__, type);
+ return -1;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
+
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "%s: tx queue %u already active\n", __func__, q);
+ return -1;
+ }
+ memset(qi, 0, sizeof(struct ath9k_tx_queue_info));
+ qi->tqi_type = type;
+ if (qinfo == NULL) {
+ qi->tqi_qflags =
+ TXQ_FLAG_TXOKINT_ENABLE
+ | TXQ_FLAG_TXERRINT_ENABLE
+ | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE;
+ qi->tqi_aifs = INIT_AIFS;
+ qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
+ qi->tqi_cwmax = INIT_CWMAX;
+ qi->tqi_shretry = INIT_SH_RETRY;
+ qi->tqi_lgretry = INIT_LG_RETRY;
+ qi->tqi_physCompBuf = 0;
+ } else {
+ qi->tqi_physCompBuf = qinfo->tqi_physCompBuf;
+ (void) ath9k_hw_set_txq_props(ah, q, qinfo);
+ }
+
+ return q;
+}
+
+static void
+ath9k_hw_set_txq_interrupts(struct ath_hal *ah,
+ struct ath9k_tx_queue_info *qi)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT,
+ "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n",
+ __func__, ahp->ah_txOkInterruptMask,
+ ahp->ah_txErrInterruptMask, ahp->ah_txDescInterruptMask,
+ ahp->ah_txEolInterruptMask, ahp->ah_txUrnInterruptMask);
+
+ REG_WRITE(ah, AR_IMR_S0,
+ SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK)
+ | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC));
+ REG_WRITE(ah, AR_IMR_S1,
+ SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR)
+ | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL));
+ REG_RMW_FIELD(ah, AR_IMR_S2,
+ AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask);
+}
+
+bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ struct ath9k_tx_queue_info *qi;
+
+ if (q >= pCap->total_queues) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+ __func__, q);
+ return false;
+ }
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
+ __func__, q);
+ return false;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: release queue %u\n",
+ __func__, q);
+
+ qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE;
+ ahp->ah_txOkInterruptMask &= ~(1 << q);
+ ahp->ah_txErrInterruptMask &= ~(1 << q);
+ ahp->ah_txDescInterruptMask &= ~(1 << q);
+ ahp->ah_txEolInterruptMask &= ~(1 << q);
+ ahp->ah_txUrnInterruptMask &= ~(1 << q);
+ ath9k_hw_set_txq_interrupts(ah, qi);
+
+ return true;
+}
+
+bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+ struct ath9k_channel *chan = ah->ah_curchan;
+ struct ath9k_tx_queue_info *qi;
+ u32 cwMin, chanCwMin, value;
+
+ if (q >= pCap->total_queues) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n",
+ __func__, q);
+ return false;
+ }
+ qi = &ahp->ah_txq[q];
+ if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n",
+ __func__, q);
+ return true;
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: reset queue %u\n", __func__, q);
+
+ if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
+ if (chan && IS_CHAN_B(chan))
+ chanCwMin = INIT_CWMIN_11B;
+ else
+ chanCwMin = INIT_CWMIN;
+
+ for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
+ } else
+ cwMin = qi->tqi_cwmin;
+
+ REG_WRITE(ah, AR_DLCL_IFS(q), SM(cwMin, AR_D_LCL_IFS_CWMIN)
+ | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX)
+ | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
+
+ REG_WRITE(ah, AR_DRETRY_LIMIT(q),
+ SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH)
+ | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG)
+ | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)
+ );
+
+ REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
+ REG_WRITE(ah, AR_DMISC(q),
+ AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
+
+ if (qi->tqi_cbrPeriod) {
+ REG_WRITE(ah, AR_QCBRCFG(q),
+ SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL)
+ | SM(qi->tqi_cbrOverflowLimit,
+ AR_Q_CBRCFG_OVF_THRESH));
+ REG_WRITE(ah, AR_QMISC(q),
+ REG_READ(ah,
+ AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | (qi->
+ tqi_cbrOverflowLimit
+ ?
+ AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN
+ :
+ 0));
+ }
+ if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
+ REG_WRITE(ah, AR_QRDYTIMECFG(q),
+ SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) |
+ AR_Q_RDYTIMECFG_EN);
+ }
+
+ REG_WRITE(ah, AR_DCHNTIME(q),
+ SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
+ (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
+
+ if (qi->tqi_burstTime
+ && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
+ REG_WRITE(ah, AR_QMISC(q),
+ REG_READ(ah,
+ AR_QMISC(q)) |
+ AR_Q_MISC_RDYTIME_EXP_POLICY);
+
+ }
+
+ if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
+ REG_WRITE(ah, AR_DMISC(q),
+ REG_READ(ah, AR_DMISC(q)) |
+ AR_D_MISC_POST_FR_BKOFF_DIS);
+ }
+ if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
+ REG_WRITE(ah, AR_DMISC(q),
+ REG_READ(ah, AR_DMISC(q)) |
+ AR_D_MISC_FRAG_BKOFF_EN);
+ }
+ switch (qi->tqi_type) {
+ case ATH9K_TX_QUEUE_BEACON:
+ REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
+ | AR_Q_MISC_FSP_DBA_GATED
+ | AR_Q_MISC_BEACON_USE
+ | AR_Q_MISC_CBR_INCR_DIS1);
+
+ REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
+ | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+ AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
+ | AR_D_MISC_BEACON_USE
+ | AR_D_MISC_POST_FR_BKOFF_DIS);
+ break;
+ case ATH9K_TX_QUEUE_CAB:
+ REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
+ | AR_Q_MISC_FSP_DBA_GATED
+ | AR_Q_MISC_CBR_INCR_DIS1
+ | AR_Q_MISC_CBR_INCR_DIS0);
+ value = (qi->tqi_readyTime
+ - (ah->ah_config.sw_beacon_response_time -
+ ah->ah_config.dma_beacon_response_time)
+ -
+ ah->ah_config.additional_swba_backoff) *
+ 1024;
+ REG_WRITE(ah, AR_QRDYTIMECFG(q),
+ value | AR_Q_RDYTIMECFG_EN);
+ REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
+ | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+ AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
+ break;
+ case ATH9K_TX_QUEUE_PSPOLL:
+ REG_WRITE(ah, AR_QMISC(q),
+ REG_READ(ah,
+ AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
+ break;
+ case ATH9K_TX_QUEUE_UAPSD:
+ REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
+ | AR_D_MISC_POST_FR_BKOFF_DIS);
+ break;
+ default:
+ break;
+ }
+
+ if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
+ REG_WRITE(ah, AR_DMISC(q),
+ REG_READ(ah, AR_DMISC(q)) |
+ SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
+ AR_D_MISC_ARB_LOCKOUT_CNTRL) |
+ AR_D_MISC_POST_FR_BKOFF_DIS);
+ }
+
+ if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
+ ahp->ah_txOkInterruptMask |= 1 << q;
+ else
+ ahp->ah_txOkInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE)
+ ahp->ah_txErrInterruptMask |= 1 << q;
+ else
+ ahp->ah_txErrInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE)
+ ahp->ah_txDescInterruptMask |= 1 << q;
+ else
+ ahp->ah_txDescInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE)
+ ahp->ah_txEolInterruptMask |= 1 << q;
+ else
+ ahp->ah_txEolInterruptMask &= ~(1 << q);
+ if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE)
+ ahp->ah_txUrnInterruptMask |= 1 << q;
+ else
+ ahp->ah_txUrnInterruptMask &= ~(1 << q);
+ ath9k_hw_set_txq_interrupts(ah, qi);
+
+ return true;
+}
+
+void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ *txqs &= ahp->ah_intrTxqs;
+ ahp->ah_intrTxqs &= ~(*txqs);
+}
+
+bool
+ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 segLen, bool firstSeg,
+ bool lastSeg, const struct ath_desc *ds0)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ if (firstSeg) {
+ ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
+ } else if (lastSeg) {
+ ads->ds_ctl0 = 0;
+ ads->ds_ctl1 = segLen;
+ ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
+ ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
+ } else {
+ ads->ds_ctl0 = 0;
+ ads->ds_ctl1 = segLen | AR_TxMore;
+ ads->ds_ctl2 = 0;
+ ads->ds_ctl3 = 0;
+ }
+ ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+ ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+ ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+ ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+ ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+ return true;
+}
+
+void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+ ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+ ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+ ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+ ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+}
+
+int
+ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ if ((ads->ds_txstatus9 & AR_TxDone) == 0)
+ return -EINPROGRESS;
+
+ ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
+ ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
+ ds->ds_txstat.ts_status = 0;
+ ds->ds_txstat.ts_flags = 0;
+
+ if (ads->ds_txstatus1 & AR_ExcessiveRetries)
+ ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
+ if (ads->ds_txstatus1 & AR_Filtered)
+ ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
+ if (ads->ds_txstatus1 & AR_FIFOUnderrun)
+ ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
+ if (ads->ds_txstatus9 & AR_TxOpExceeded)
+ ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
+ if (ads->ds_txstatus1 & AR_TxTimerExpired)
+ ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
+
+ if (ads->ds_txstatus1 & AR_DescCfgErr)
+ ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
+ if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
+ ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
+ ath9k_hw_updatetxtriglevel(ah, true);
+ }
+ if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
+ ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
+ ath9k_hw_updatetxtriglevel(ah, true);
+ }
+ if (ads->ds_txstatus0 & AR_TxBaStatus) {
+ ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
+ ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
+ ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
+ }
+
+ ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
+ switch (ds->ds_txstat.ts_rateindex) {
+ case 0:
+ ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
+ break;
+ case 1:
+ ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
+ break;
+ case 2:
+ ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
+ break;
+ case 3:
+ ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
+ break;
+ }
+
+ ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
+ ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
+ ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
+ ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
+ ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
+ ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
+ ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
+ ds->ds_txstat.evm0 = ads->AR_TxEVM0;
+ ds->ds_txstat.evm1 = ads->AR_TxEVM1;
+ ds->ds_txstat.evm2 = ads->AR_TxEVM2;
+ ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
+ ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
+ ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
+ ds->ds_txstat.ts_antenna = 1;
+
+ return 0;
+}
+
+void
+ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
+ u32 keyIx, enum ath9k_key_type keyType, u32 flags)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ txPower += ahp->ah_txPowerIndexOffset;
+ if (txPower > 63)
+ txPower = 63;
+
+ ads->ds_ctl0 = (pktLen & AR_FrameLen)
+ | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+ | SM(txPower, AR_XmitPower)
+ | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+ | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
+ | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
+ | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
+
+ ads->ds_ctl1 =
+ (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
+ | SM(type, AR_FrameType)
+ | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
+ | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
+ | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+
+ ads->ds_ctl6 = SM(keyType, AR_EncrType);
+
+ if (AR_SREV_9285(ah)) {
+
+ ads->ds_ctl8 = 0;
+ ads->ds_ctl9 = 0;
+ ads->ds_ctl10 = 0;
+ ads->ds_ctl11 = 0;
+ }
+}
+
+void
+ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds,
+ struct ath_desc *lastds,
+ u32 durUpdateEn, u32 rtsctsRate,
+ u32 rtsctsDuration,
+ struct ath9k_11n_rate_series series[],
+ u32 nseries, u32 flags)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+ struct ar5416_desc *last_ads = AR5416DESC(lastds);
+ u32 ds_ctl0;
+
+ (void) nseries;
+ (void) rtsctsDuration;
+
+ if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
+ ds_ctl0 = ads->ds_ctl0;
+
+ if (flags & ATH9K_TXDESC_RTSENA) {
+ ds_ctl0 &= ~AR_CTSEnable;
+ ds_ctl0 |= AR_RTSEnable;
+ } else {
+ ds_ctl0 &= ~AR_RTSEnable;
+ ds_ctl0 |= AR_CTSEnable;
+ }
+
+ ads->ds_ctl0 = ds_ctl0;
+ } else {
+ ads->ds_ctl0 =
+ (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
+ }
+
+ ads->ds_ctl2 = set11nTries(series, 0)
+ | set11nTries(series, 1)
+ | set11nTries(series, 2)
+ | set11nTries(series, 3)
+ | (durUpdateEn ? AR_DurUpdateEna : 0)
+ | SM(0, AR_BurstDur);
+
+ ads->ds_ctl3 = set11nRate(series, 0)
+ | set11nRate(series, 1)
+ | set11nRate(series, 2)
+ | set11nRate(series, 3);
+
+ ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
+ | set11nPktDurRTSCTS(series, 1);
+
+ ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
+ | set11nPktDurRTSCTS(series, 3);
+
+ ads->ds_ctl7 = set11nRateFlags(series, 0)
+ | set11nRateFlags(series, 1)
+ | set11nRateFlags(series, 2)
+ | set11nRateFlags(series, 3)
+ | SM(rtsctsRate, AR_RTSCTSRate);
+ last_ads->ds_ctl2 = ads->ds_ctl2;
+ last_ads->ds_ctl3 = ads->ds_ctl3;
+}
+
+void
+ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds,
+ u32 aggrLen)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+
+ ads->ds_ctl6 &= ~AR_AggrLen;
+ ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
+}
+
+void
+ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds,
+ u32 numDelims)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+ unsigned int ctl6;
+
+ ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+
+ ctl6 = ads->ds_ctl6;
+ ctl6 &= ~AR_PadDelim;
+ ctl6 |= SM(numDelims, AR_PadDelim);
+ ads->ds_ctl6 = ctl6;
+}
+
+void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ ads->ds_ctl1 |= AR_IsAggr;
+ ads->ds_ctl1 &= ~AR_MoreAggr;
+ ads->ds_ctl6 &= ~AR_PadDelim;
+}
+
+void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
+}
+
+void
+ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds,
+ u32 burstDuration)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ ads->ds_ctl2 &= ~AR_BurstDur;
+ ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
+}
+
+void
+ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds,
+ u32 vmf)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ if (vmf)
+ ads->ds_ctl0 |= AR_VirtMoreFrag;
+ else
+ ads->ds_ctl0 &= ~AR_VirtMoreFrag;
+}
+
+void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp)
+{
+ REG_WRITE(ah, AR_RXDP, rxdp);
+}
+
+void ath9k_hw_rxena(struct ath_hal *ah)
+{
+ REG_WRITE(ah, AR_CR, AR_CR_RXE);
+}
+
+bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set)
+{
+ if (set) {
+
+ REG_SET_BIT(ah, AR_DIAG_SW,
+ (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+ if (!ath9k_hw_wait
+ (ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) {
+ u32 reg;
+
+ REG_CLR_BIT(ah, AR_DIAG_SW,
+ (AR_DIAG_RX_DIS |
+ AR_DIAG_RX_ABORT));
+
+ reg = REG_READ(ah, AR_OBS_BUS_1);
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "%s: rx failed to go idle in 10 ms RXSM=0x%x\n",
+ __func__, reg);
+
+ return false;
+ }
+ } else {
+ REG_CLR_BIT(ah, AR_DIAG_SW,
+ (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+ }
+
+ return true;
+}
+
+void
+ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0,
+ u32 filter1)
+{
+ REG_WRITE(ah, AR_MCAST_FIL0, filter0);
+ REG_WRITE(ah, AR_MCAST_FIL1, filter1);
+}
+
+bool
+ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 size, u32 flags)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+ struct ath9k_hw_capabilities *pCap = &ah->ah_caps;
+
+ ads->ds_ctl1 = size & AR_BufLen;
+ if (flags & ATH9K_RXDESC_INTREQ)
+ ads->ds_ctl1 |= AR_RxIntrReq;
+
+ ads->ds_rxstatus8 &= ~AR_RxDone;
+ if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+ memset(&(ads->u), 0, sizeof(ads->u));
+ return true;
+}
+
+int
+ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds,
+ u32 pa, struct ath_desc *nds, u64 tsf)
+{
+ struct ar5416_desc ads;
+ struct ar5416_desc *adsp = AR5416DESC(ds);
+
+ if ((adsp->ds_rxstatus8 & AR_RxDone) == 0)
+ return -EINPROGRESS;
+
+ ads.u.rx = adsp->u.rx;
+
+ ds->ds_rxstat.rs_status = 0;
+ ds->ds_rxstat.rs_flags = 0;
+
+ ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
+ ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
+
+ ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+ ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
+ ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
+ ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
+ ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
+ ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
+ ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
+ if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
+ ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
+ else
+ ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
+
+ ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
+ ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
+
+ ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
+ ds->ds_rxstat.rs_moreaggr =
+ (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
+ ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
+ ds->ds_rxstat.rs_flags =
+ (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
+ ds->ds_rxstat.rs_flags |=
+ (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
+
+ if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
+ ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
+ if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
+ ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
+ if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
+ ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
+
+ if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
+
+ if (ads.ds_rxstatus8 & AR_CRCErr)
+ ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
+ else if (ads.ds_rxstatus8 & AR_PHYErr) {
+ u32 phyerr;
+
+ ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
+ phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
+ ds->ds_rxstat.rs_phyerr = phyerr;
+ } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
+ ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
+ else if (ads.ds_rxstatus8 & AR_MichaelErr)
+ ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
+ }
+
+ return 0;
+}
+
+static void ath9k_hw_setup_rate_table(struct ath_hal *ah,
+ struct ath9k_rate_table *rt)
+{
+ int i;
+
+ if (rt->rateCodeToIndex[0] != 0)
+ return;
+ for (i = 0; i < 256; i++)
+ rt->rateCodeToIndex[i] = (u8) -1;
+ for (i = 0; i < rt->rateCount; i++) {
+ u8 code = rt->info[i].rateCode;
+ u8 cix = rt->info[i].controlRate;
+
+ rt->rateCodeToIndex[code] = i;
+ rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i;
+
+ rt->info[i].lpAckDuration =
+ ath9k_hw_computetxtime(ah, rt,
+ WLAN_CTRL_FRAME_SIZE,
+ cix,
+ false);
+ rt->info[i].spAckDuration =
+ ath9k_hw_computetxtime(ah, rt,
+ WLAN_CTRL_FRAME_SIZE,
+ cix,
+ true);
+ }
+}
+
+const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah,
+ u32 mode)
+{
+ struct ath9k_rate_table *rt;
+ switch (mode) {
+ case ATH9K_MODE_11A:
+ rt = &ar5416_11a_table;
+ break;
+ case ATH9K_MODE_11B:
+ rt = &ar5416_11b_table;
+ break;
+ case ATH9K_MODE_11G:
+ rt = &ar5416_11g_table;
+ break;
+ case ATH9K_MODE_11NG_HT20:
+ case ATH9K_MODE_11NG_HT40PLUS:
+ case ATH9K_MODE_11NG_HT40MINUS:
+ rt = &ar5416_11ng_table;
+ break;
+ case ATH9K_MODE_11NA_HT20:
+ case ATH9K_MODE_11NA_HT40PLUS:
+ case ATH9K_MODE_11NA_HT40MINUS:
+ rt = &ar5416_11na_table;
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n",
+ __func__, mode);
+ return NULL;
+ }
+ ath9k_hw_setup_rate_table(ah, rt);
+ return rt;
+}
+
+static const char *ath9k_hw_devname(u16 devid)
+{
+ switch (devid) {
+ case AR5416_DEVID_PCI:
+ case AR5416_DEVID_PCIE:
+ return "Atheros 5416";
+ case AR9160_DEVID_PCI:
+ return "Atheros 9160";
+ case AR9280_DEVID_PCI:
+ case AR9280_DEVID_PCIE:
+ return "Atheros 9280";
+ }
+ return NULL;
+}
+
+const char *ath9k_hw_probe(u16 vendorid, u16 devid)
+{
+ return vendorid == ATHEROS_VENDOR_ID ?
+ ath9k_hw_devname(devid) : NULL;
+}
+
+struct ath_hal *ath9k_hw_attach(u16 devid,
+ struct ath_softc *sc,
+ void __iomem *mem,
+ int *error)
+{
+ struct ath_hal *ah = NULL;
+
+ switch (devid) {
+ case AR5416_DEVID_PCI:
+ case AR5416_DEVID_PCIE:
+ case AR9160_DEVID_PCI:
+ case AR9280_DEVID_PCI:
+ case AR9280_DEVID_PCIE:
+ ah = ath9k_hw_do_attach(devid, sc, mem, error);
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+ "devid=0x%x not supported.\n", devid);
+ ah = NULL;
+ *error = -ENXIO;
+ break;
+ }
+ if (ah != NULL) {
+ ah->ah_devid = ah->ah_devid;
+ ah->ah_subvendorid = ah->ah_subvendorid;
+ ah->ah_macVersion = ah->ah_macVersion;
+ ah->ah_macRev = ah->ah_macRev;
+ ah->ah_phyRev = ah->ah_phyRev;
+ ah->ah_analog5GhzRev = ah->ah_analog5GhzRev;
+ ah->ah_analog2GhzRev = ah->ah_analog2GhzRev;
+ }
+ return ah;
+}
+
+u16
+ath9k_hw_computetxtime(struct ath_hal *ah,
+ const struct ath9k_rate_table *rates,
+ u32 frameLen, u16 rateix,
+ bool shortPreamble)
+{
+ u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
+ u32 kbps;
+
+ kbps = rates->info[rateix].rateKbps;
+
+ if (kbps == 0)
+ return 0;
+ switch (rates->info[rateix].phy) {
+
+ case PHY_CCK:
+ phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
+ if (shortPreamble && rates->info[rateix].shortPreamble)
+ phyTime >>= 1;
+ numBits = frameLen << 3;
+ txTime = CCK_SIFS_TIME + phyTime
+ + ((numBits * 1000) / kbps);
+ break;
+ case PHY_OFDM:
+ if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) {
+ bitsPerSymbol =
+ (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
+
+ numBits = OFDM_PLCP_BITS + (frameLen << 3);
+ numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+ txTime = OFDM_SIFS_TIME_QUARTER
+ + OFDM_PREAMBLE_TIME_QUARTER
+ + (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
+ } else if (ah->ah_curchan &&
+ IS_CHAN_HALF_RATE(ah->ah_curchan)) {
+ bitsPerSymbol =
+ (kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
+
+ numBits = OFDM_PLCP_BITS + (frameLen << 3);
+ numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+ txTime = OFDM_SIFS_TIME_HALF +
+ OFDM_PREAMBLE_TIME_HALF
+ + (numSymbols * OFDM_SYMBOL_TIME_HALF);
+ } else {
+ bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000;
+
+ numBits = OFDM_PLCP_BITS + (frameLen << 3);
+ numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
+ txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME
+ + (numSymbols * OFDM_SYMBOL_TIME);
+ }
+ break;
+
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO,
+ "%s: unknown phy %u (rate ix %u)\n", __func__,
+ rates->info[rateix].phy, rateix);
+ txTime = 0;
+ break;
+ }
+ return txTime;
+}
+
+u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags)
+{
+ if (flags & CHANNEL_2GHZ) {
+ if (freq == 2484)
+ return 14;
+ if (freq < 2484)
+ return (freq - 2407) / 5;
+ else
+ return 15 + ((freq - 2512) / 20);
+ } else if (flags & CHANNEL_5GHZ) {
+ if (ath9k_regd_is_public_safety_sku(ah) &&
+ IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
+ return ((freq * 10) +
+ (((freq % 5) == 2) ? 5 : 0) - 49400) / 5;
+ } else if ((flags & CHANNEL_A) && (freq <= 5000)) {
+ return (freq - 4000) / 5;
+ } else {
+ return (freq - 5000) / 5;
+ }
+ } else {
+ if (freq == 2484)
+ return 14;
+ if (freq < 2484)
+ return (freq - 2407) / 5;
+ if (freq < 5000) {
+ if (ath9k_regd_is_public_safety_sku(ah)
+ && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) {
+ return ((freq * 10) +
+ (((freq % 5) ==
+ 2) ? 5 : 0) - 49400) / 5;
+ } else if (freq > 4900) {
+ return (freq - 4000) / 5;
+ } else {
+ return 15 + ((freq - 2512) / 20);
+ }
+ }
+ return (freq - 5000) / 5;
+ }
+}
+
+int16_t
+ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+ struct ath9k_channel *ichan;
+
+ ichan = ath9k_regd_check_channel(ah, chan);
+ if (ichan == NULL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+ "%s: invalid channel %u/0x%x; no mapping\n",
+ __func__, chan->channel, chan->channelFlags);
+ return 0;
+ }
+ if (ichan->rawNoiseFloor == 0) {
+ enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
+ return NOISE_FLOOR[mode];
+ } else
+ return ichan->rawNoiseFloor;
+}
+
+bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (setting)
+ ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF;
+ else
+ ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF;
+ return true;
+}
+
+bool ath9k_hw_phycounters(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ return ahp->ah_hasHwPhyCounters ? true : false;
+}
+
+u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q)
+{
+ return REG_READ(ah, AR_QTXDP(q));
+}
+
+bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q,
+ u32 txdp)
+{
+ REG_WRITE(ah, AR_QTXDP(q), txdp);
+
+ return true;
+}
+
+bool ath9k_hw_txstart(struct ath_hal *ah, u32 q)
+{
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q);
+
+ REG_WRITE(ah, AR_Q_TXE, 1 << q);
+
+ return true;
+}
+
+u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q)
+{
+ u32 npend;
+
+ npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT;
+ if (npend == 0) {
+
+ if (REG_READ(ah, AR_Q_TXE) & (1 << q))
+ npend = 1;
+ }
+ return npend;
+}
+
+bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q)
+{
+ u32 wait;
+
+ REG_WRITE(ah, AR_Q_TXD, 1 << q);
+
+ for (wait = 1000; wait != 0; wait--) {
+ if (ath9k_hw_numtxpending(ah, q) == 0)
+ break;
+ udelay(100);
+ }
+
+ if (ath9k_hw_numtxpending(ah, q)) {
+ u32 tsfLow, j;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "%s: Num of pending TX Frames %d on Q %d\n",
+ __func__, ath9k_hw_numtxpending(ah, q), q);
+
+ for (j = 0; j < 2; j++) {
+ tsfLow = REG_READ(ah, AR_TSF_L32);
+ REG_WRITE(ah, AR_QUIET2,
+ SM(10, AR_QUIET2_QUIET_DUR));
+ REG_WRITE(ah, AR_QUIET_PERIOD, 100);
+ REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10);
+ REG_SET_BIT(ah, AR_TIMER_MODE,
+ AR_QUIET_TIMER_EN);
+
+ if ((REG_READ(ah, AR_TSF_L32) >> 10) ==
+ (tsfLow >> 10)) {
+ break;
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
+ "%s: TSF have moved while trying to set "
+ "quiet time TSF: 0x%08x\n",
+ __func__, tsfLow);
+ }
+
+ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+
+ udelay(200);
+ REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN);
+
+ wait = 1000;
+
+ while (ath9k_hw_numtxpending(ah, q)) {
+ if ((--wait) == 0) {
+ DPRINTF(ah->ah_sc, ATH_DBG_XMIT,
+ "%s: Failed to stop Tx DMA in 100 "
+ "msec after killing last frame\n",
+ __func__);
+ break;
+ }
+ udelay(100);
+ }
+
+ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH);
+ }
+
+ REG_WRITE(ah, AR_Q_TXD, 0);
+ return wait != 0;
+}
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h
new file mode 100644
index 00000000000..ae680f21ba7
--- /dev/null
+++ b/drivers/net/wireless/ath9k/hw.h
@@ -0,0 +1,969 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef HW_H
+#define HW_H
+
+#include <linux/if_ether.h>
+#include <linux/delay.h>
+
+struct ar5416_desc {
+ u32 ds_link;
+ u32 ds_data;
+ u32 ds_ctl0;
+ u32 ds_ctl1;
+ union {
+ struct {
+ u32 ctl2;
+ u32 ctl3;
+ u32 ctl4;
+ u32 ctl5;
+ u32 ctl6;
+ u32 ctl7;
+ u32 ctl8;
+ u32 ctl9;
+ u32 ctl10;
+ u32 ctl11;
+ u32 status0;
+ u32 status1;
+ u32 status2;
+ u32 status3;
+ u32 status4;
+ u32 status5;
+ u32 status6;
+ u32 status7;
+ u32 status8;
+ u32 status9;
+ } tx;
+ struct {
+ u32 status0;
+ u32 status1;
+ u32 status2;
+ u32 status3;
+ u32 status4;
+ u32 status5;
+ u32 status6;
+ u32 status7;
+ u32 status8;
+ } rx;
+ } u;
+} __packed;
+
+#define AR5416DESC(_ds) ((struct ar5416_desc *)(_ds))
+#define AR5416DESC_CONST(_ds) ((const struct ar5416_desc *)(_ds))
+
+#define ds_ctl2 u.tx.ctl2
+#define ds_ctl3 u.tx.ctl3
+#define ds_ctl4 u.tx.ctl4
+#define ds_ctl5 u.tx.ctl5
+#define ds_ctl6 u.tx.ctl6
+#define ds_ctl7 u.tx.ctl7
+#define ds_ctl8 u.tx.ctl8
+#define ds_ctl9 u.tx.ctl9
+#define ds_ctl10 u.tx.ctl10
+#define ds_ctl11 u.tx.ctl11
+
+#define ds_txstatus0 u.tx.status0
+#define ds_txstatus1 u.tx.status1
+#define ds_txstatus2 u.tx.status2
+#define ds_txstatus3 u.tx.status3
+#define ds_txstatus4 u.tx.status4
+#define ds_txstatus5 u.tx.status5
+#define ds_txstatus6 u.tx.status6
+#define ds_txstatus7 u.tx.status7
+#define ds_txstatus8 u.tx.status8
+#define ds_txstatus9 u.tx.status9
+
+#define ds_rxstatus0 u.rx.status0
+#define ds_rxstatus1 u.rx.status1
+#define ds_rxstatus2 u.rx.status2
+#define ds_rxstatus3 u.rx.status3
+#define ds_rxstatus4 u.rx.status4
+#define ds_rxstatus5 u.rx.status5
+#define ds_rxstatus6 u.rx.status6
+#define ds_rxstatus7 u.rx.status7
+#define ds_rxstatus8 u.rx.status8
+
+#define AR_FrameLen 0x00000fff
+#define AR_VirtMoreFrag 0x00001000
+#define AR_TxCtlRsvd00 0x0000e000
+#define AR_XmitPower 0x003f0000
+#define AR_XmitPower_S 16
+#define AR_RTSEnable 0x00400000
+#define AR_VEOL 0x00800000
+#define AR_ClrDestMask 0x01000000
+#define AR_TxCtlRsvd01 0x1e000000
+#define AR_TxIntrReq 0x20000000
+#define AR_DestIdxValid 0x40000000
+#define AR_CTSEnable 0x80000000
+
+#define AR_BufLen 0x00000fff
+#define AR_TxMore 0x00001000
+#define AR_DestIdx 0x000fe000
+#define AR_DestIdx_S 13
+#define AR_FrameType 0x00f00000
+#define AR_FrameType_S 20
+#define AR_NoAck 0x01000000
+#define AR_InsertTS 0x02000000
+#define AR_CorruptFCS 0x04000000
+#define AR_ExtOnly 0x08000000
+#define AR_ExtAndCtl 0x10000000
+#define AR_MoreAggr 0x20000000
+#define AR_IsAggr 0x40000000
+
+#define AR_BurstDur 0x00007fff
+#define AR_BurstDur_S 0
+#define AR_DurUpdateEna 0x00008000
+#define AR_XmitDataTries0 0x000f0000
+#define AR_XmitDataTries0_S 16
+#define AR_XmitDataTries1 0x00f00000
+#define AR_XmitDataTries1_S 20
+#define AR_XmitDataTries2 0x0f000000
+#define AR_XmitDataTries2_S 24
+#define AR_XmitDataTries3 0xf0000000
+#define AR_XmitDataTries3_S 28
+
+#define AR_XmitRate0 0x000000ff
+#define AR_XmitRate0_S 0
+#define AR_XmitRate1 0x0000ff00
+#define AR_XmitRate1_S 8
+#define AR_XmitRate2 0x00ff0000
+#define AR_XmitRate2_S 16
+#define AR_XmitRate3 0xff000000
+#define AR_XmitRate3_S 24
+
+#define AR_PacketDur0 0x00007fff
+#define AR_PacketDur0_S 0
+#define AR_RTSCTSQual0 0x00008000
+#define AR_PacketDur1 0x7fff0000
+#define AR_PacketDur1_S 16
+#define AR_RTSCTSQual1 0x80000000
+
+#define AR_PacketDur2 0x00007fff
+#define AR_PacketDur2_S 0
+#define AR_RTSCTSQual2 0x00008000
+#define AR_PacketDur3 0x7fff0000
+#define AR_PacketDur3_S 16
+#define AR_RTSCTSQual3 0x80000000
+
+#define AR_AggrLen 0x0000ffff
+#define AR_AggrLen_S 0
+#define AR_TxCtlRsvd60 0x00030000
+#define AR_PadDelim 0x03fc0000
+#define AR_PadDelim_S 18
+#define AR_EncrType 0x0c000000
+#define AR_EncrType_S 26
+#define AR_TxCtlRsvd61 0xf0000000
+
+#define AR_2040_0 0x00000001
+#define AR_GI0 0x00000002
+#define AR_ChainSel0 0x0000001c
+#define AR_ChainSel0_S 2
+#define AR_2040_1 0x00000020
+#define AR_GI1 0x00000040
+#define AR_ChainSel1 0x00000380
+#define AR_ChainSel1_S 7
+#define AR_2040_2 0x00000400
+#define AR_GI2 0x00000800
+#define AR_ChainSel2 0x00007000
+#define AR_ChainSel2_S 12
+#define AR_2040_3 0x00008000
+#define AR_GI3 0x00010000
+#define AR_ChainSel3 0x000e0000
+#define AR_ChainSel3_S 17
+#define AR_RTSCTSRate 0x0ff00000
+#define AR_RTSCTSRate_S 20
+#define AR_TxCtlRsvd70 0xf0000000
+
+#define AR_TxRSSIAnt00 0x000000ff
+#define AR_TxRSSIAnt00_S 0
+#define AR_TxRSSIAnt01 0x0000ff00
+#define AR_TxRSSIAnt01_S 8
+#define AR_TxRSSIAnt02 0x00ff0000
+#define AR_TxRSSIAnt02_S 16
+#define AR_TxStatusRsvd00 0x3f000000
+#define AR_TxBaStatus 0x40000000
+#define AR_TxStatusRsvd01 0x80000000
+
+#define AR_FrmXmitOK 0x00000001
+#define AR_ExcessiveRetries 0x00000002
+#define AR_FIFOUnderrun 0x00000004
+#define AR_Filtered 0x00000008
+#define AR_RTSFailCnt 0x000000f0
+#define AR_RTSFailCnt_S 4
+#define AR_DataFailCnt 0x00000f00
+#define AR_DataFailCnt_S 8
+#define AR_VirtRetryCnt 0x0000f000
+#define AR_VirtRetryCnt_S 12
+#define AR_TxDelimUnderrun 0x00010000
+#define AR_TxDataUnderrun 0x00020000
+#define AR_DescCfgErr 0x00040000
+#define AR_TxTimerExpired 0x00080000
+#define AR_TxStatusRsvd10 0xfff00000
+
+#define AR_SendTimestamp ds_txstatus2
+#define AR_BaBitmapLow ds_txstatus3
+#define AR_BaBitmapHigh ds_txstatus4
+
+#define AR_TxRSSIAnt10 0x000000ff
+#define AR_TxRSSIAnt10_S 0
+#define AR_TxRSSIAnt11 0x0000ff00
+#define AR_TxRSSIAnt11_S 8
+#define AR_TxRSSIAnt12 0x00ff0000
+#define AR_TxRSSIAnt12_S 16
+#define AR_TxRSSICombined 0xff000000
+#define AR_TxRSSICombined_S 24
+
+#define AR_TxEVM0 ds_txstatus5
+#define AR_TxEVM1 ds_txstatus6
+#define AR_TxEVM2 ds_txstatus7
+
+#define AR_TxDone 0x00000001
+#define AR_SeqNum 0x00001ffe
+#define AR_SeqNum_S 1
+#define AR_TxStatusRsvd80 0x0001e000
+#define AR_TxOpExceeded 0x00020000
+#define AR_TxStatusRsvd81 0x001c0000
+#define AR_FinalTxIdx 0x00600000
+#define AR_FinalTxIdx_S 21
+#define AR_TxStatusRsvd82 0x01800000
+#define AR_PowerMgmt 0x02000000
+#define AR_TxStatusRsvd83 0xfc000000
+
+#define AR_RxCTLRsvd00 0xffffffff
+
+#define AR_BufLen 0x00000fff
+#define AR_RxCtlRsvd00 0x00001000
+#define AR_RxIntrReq 0x00002000
+#define AR_RxCtlRsvd01 0xffffc000
+
+#define AR_RxRSSIAnt00 0x000000ff
+#define AR_RxRSSIAnt00_S 0
+#define AR_RxRSSIAnt01 0x0000ff00
+#define AR_RxRSSIAnt01_S 8
+#define AR_RxRSSIAnt02 0x00ff0000
+#define AR_RxRSSIAnt02_S 16
+#define AR_RxRate 0xff000000
+#define AR_RxRate_S 24
+#define AR_RxStatusRsvd00 0xff000000
+
+#define AR_DataLen 0x00000fff
+#define AR_RxMore 0x00001000
+#define AR_NumDelim 0x003fc000
+#define AR_NumDelim_S 14
+#define AR_RxStatusRsvd10 0xff800000
+
+#define AR_RcvTimestamp ds_rxstatus2
+
+#define AR_GI 0x00000001
+#define AR_2040 0x00000002
+#define AR_Parallel40 0x00000004
+#define AR_Parallel40_S 2
+#define AR_RxStatusRsvd30 0x000000f8
+#define AR_RxAntenna 0xffffff00
+#define AR_RxAntenna_S 8
+
+#define AR_RxRSSIAnt10 0x000000ff
+#define AR_RxRSSIAnt10_S 0
+#define AR_RxRSSIAnt11 0x0000ff00
+#define AR_RxRSSIAnt11_S 8
+#define AR_RxRSSIAnt12 0x00ff0000
+#define AR_RxRSSIAnt12_S 16
+#define AR_RxRSSICombined 0xff000000
+#define AR_RxRSSICombined_S 24
+
+#define AR_RxEVM0 ds_rxstatus4
+#define AR_RxEVM1 ds_rxstatus5
+#define AR_RxEVM2 ds_rxstatus6
+
+#define AR_RxDone 0x00000001
+#define AR_RxFrameOK 0x00000002
+#define AR_CRCErr 0x00000004
+#define AR_DecryptCRCErr 0x00000008
+#define AR_PHYErr 0x00000010
+#define AR_MichaelErr 0x00000020
+#define AR_PreDelimCRCErr 0x00000040
+#define AR_RxStatusRsvd70 0x00000080
+#define AR_RxKeyIdxValid 0x00000100
+#define AR_KeyIdx 0x0000fe00
+#define AR_KeyIdx_S 9
+#define AR_PHYErrCode 0x0000ff00
+#define AR_PHYErrCode_S 8
+#define AR_RxMoreAggr 0x00010000
+#define AR_RxAggr 0x00020000
+#define AR_PostDelimCRCErr 0x00040000
+#define AR_RxStatusRsvd71 0x3ff80000
+#define AR_DecryptBusyErr 0x40000000
+#define AR_KeyMiss 0x80000000
+
+#define AR5416_MAGIC 0x19641014
+
+#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \
+ MS(ads->ds_rxstatus0, AR_RxRate) : \
+ (ads->ds_rxstatus3 >> 2) & 0xFF)
+#define RXSTATUS_DUPLICATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ? \
+ MS(ads->ds_rxstatus3, AR_Parallel40) : \
+ (ads->ds_rxstatus3 >> 10) & 0x1)
+
+#define set11nTries(_series, _index) \
+ (SM((_series)[_index].Tries, AR_XmitDataTries##_index))
+
+#define set11nRate(_series, _index) \
+ (SM((_series)[_index].Rate, AR_XmitRate##_index))
+
+#define set11nPktDurRTSCTS(_series, _index) \
+ (SM((_series)[_index].PktDuration, AR_PacketDur##_index) | \
+ ((_series)[_index].RateFlags & ATH9K_RATESERIES_RTS_CTS ? \
+ AR_RTSCTSQual##_index : 0))
+
+#define set11nRateFlags(_series, _index) \
+ (((_series)[_index].RateFlags & ATH9K_RATESERIES_2040 ? \
+ AR_2040_##_index : 0) \
+ |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ? \
+ AR_GI##_index : 0) \
+ |SM((_series)[_index].ChSel, AR_ChainSel##_index))
+
+#define AR_SREV_9100(ah) ((ah->ah_macVersion) == AR_SREV_VERSION_9100)
+
+#define INIT_CONFIG_STATUS 0x00000000
+#define INIT_RSSI_THR 0x00000700
+#define INIT_BCON_CNTRL_REG 0x00000000
+
+#define MIN_TX_FIFO_THRESHOLD 0x1
+#define MAX_TX_FIFO_THRESHOLD ((4096 / 64) - 1)
+#define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD
+
+#define NUM_CORNER_FIX_BITS_2133 7
+#define CCK_OFDM_GAIN_DELTA 15
+
+struct ar5416AniState {
+ struct ath9k_channel c;
+ u8 noiseImmunityLevel;
+ u8 spurImmunityLevel;
+ u8 firstepLevel;
+ u8 ofdmWeakSigDetectOff;
+ u8 cckWeakSigThreshold;
+ u32 listenTime;
+ u32 ofdmTrigHigh;
+ u32 ofdmTrigLow;
+ int32_t cckTrigHigh;
+ int32_t cckTrigLow;
+ int32_t rssiThrLow;
+ int32_t rssiThrHigh;
+ u32 noiseFloor;
+ u32 txFrameCount;
+ u32 rxFrameCount;
+ u32 cycleCount;
+ u32 ofdmPhyErrCount;
+ u32 cckPhyErrCount;
+ u32 ofdmPhyErrBase;
+ u32 cckPhyErrBase;
+ int16_t pktRssi[2];
+ int16_t ofdmErrRssi[2];
+ int16_t cckErrRssi[2];
+};
+
+#define HAL_PROCESS_ANI 0x00000001
+#define HAL_RADAR_EN 0x80000000
+#define HAL_AR_EN 0x40000000
+
+#define DO_ANI(ah) \
+ ((AH5416(ah)->ah_procPhyErr & HAL_PROCESS_ANI))
+
+struct ar5416Stats {
+ u32 ast_ani_niup;
+ u32 ast_ani_nidown;
+ u32 ast_ani_spurup;
+ u32 ast_ani_spurdown;
+ u32 ast_ani_ofdmon;
+ u32 ast_ani_ofdmoff;
+ u32 ast_ani_cckhigh;
+ u32 ast_ani_ccklow;
+ u32 ast_ani_stepup;
+ u32 ast_ani_stepdown;
+ u32 ast_ani_ofdmerrs;
+ u32 ast_ani_cckerrs;
+ u32 ast_ani_reset;
+ u32 ast_ani_lzero;
+ u32 ast_ani_lneg;
+ struct ath9k_mib_stats ast_mibstats;
+ struct ath9k_node_stats ast_nodestats;
+};
+
+#define AR5416_OPFLAGS_11A 0x01
+#define AR5416_OPFLAGS_11G 0x02
+#define AR5416_OPFLAGS_N_5G_HT40 0x04
+#define AR5416_OPFLAGS_N_2G_HT40 0x08
+#define AR5416_OPFLAGS_N_5G_HT20 0x10
+#define AR5416_OPFLAGS_N_2G_HT20 0x20
+
+#define EEP_RFSILENT_ENABLED 0x0001
+#define EEP_RFSILENT_ENABLED_S 0
+#define EEP_RFSILENT_POLARITY 0x0002
+#define EEP_RFSILENT_POLARITY_S 1
+#define EEP_RFSILENT_GPIO_SEL 0x001c
+#define EEP_RFSILENT_GPIO_SEL_S 2
+
+#define AR5416_EEP_NO_BACK_VER 0x1
+#define AR5416_EEP_VER 0xE
+#define AR5416_EEP_VER_MINOR_MASK 0x0FFF
+#define AR5416_EEP_MINOR_VER_2 0x2
+#define AR5416_EEP_MINOR_VER_3 0x3
+#define AR5416_EEP_MINOR_VER_7 0x7
+#define AR5416_EEP_MINOR_VER_9 0x9
+
+#define AR5416_EEP_START_LOC 256
+#define AR5416_NUM_5G_CAL_PIERS 8
+#define AR5416_NUM_2G_CAL_PIERS 4
+#define AR5416_NUM_5G_20_TARGET_POWERS 8
+#define AR5416_NUM_5G_40_TARGET_POWERS 8
+#define AR5416_NUM_2G_CCK_TARGET_POWERS 3
+#define AR5416_NUM_2G_20_TARGET_POWERS 4
+#define AR5416_NUM_2G_40_TARGET_POWERS 4
+#define AR5416_NUM_CTLS 24
+#define AR5416_NUM_BAND_EDGES 8
+#define AR5416_NUM_PD_GAINS 4
+#define AR5416_PD_GAINS_IN_MASK 4
+#define AR5416_PD_GAIN_ICEPTS 5
+#define AR5416_EEPROM_MODAL_SPURS 5
+#define AR5416_MAX_RATE_POWER 63
+#define AR5416_NUM_PDADC_VALUES 128
+#define AR5416_NUM_RATES 16
+#define AR5416_BCHAN_UNUSED 0xFF
+#define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
+#define AR5416_EEPMISC_BIG_ENDIAN 0x01
+#define AR5416_MAX_CHAINS 3
+#define AR5416_ANT_16S 25
+
+#define AR5416_NUM_ANT_CHAIN_FIELDS 7
+#define AR5416_NUM_ANT_COMMON_FIELDS 4
+#define AR5416_SIZE_ANT_CHAIN_FIELD 3
+#define AR5416_SIZE_ANT_COMMON_FIELD 4
+#define AR5416_ANT_CHAIN_MASK 0x7
+#define AR5416_ANT_COMMON_MASK 0xf
+#define AR5416_CHAIN_0_IDX 0
+#define AR5416_CHAIN_1_IDX 1
+#define AR5416_CHAIN_2_IDX 2
+
+#define AR5416_PWR_TABLE_OFFSET -5
+#define AR5416_LEGACY_CHAINMASK 1
+
+enum eeprom_param {
+ EEP_NFTHRESH_5,
+ EEP_NFTHRESH_2,
+ EEP_MAC_MSW,
+ EEP_MAC_MID,
+ EEP_MAC_LSW,
+ EEP_REG_0,
+ EEP_REG_1,
+ EEP_OP_CAP,
+ EEP_OP_MODE,
+ EEP_RF_SILENT,
+ EEP_OB_5,
+ EEP_DB_5,
+ EEP_OB_2,
+ EEP_DB_2,
+ EEP_MINOR_REV,
+ EEP_TX_MASK,
+ EEP_RX_MASK,
+};
+
+enum ar5416_rates {
+ rate6mb, rate9mb, rate12mb, rate18mb,
+ rate24mb, rate36mb, rate48mb, rate54mb,
+ rate1l, rate2l, rate2s, rate5_5l,
+ rate5_5s, rate11l, rate11s, rateXr,
+ rateHt20_0, rateHt20_1, rateHt20_2, rateHt20_3,
+ rateHt20_4, rateHt20_5, rateHt20_6, rateHt20_7,
+ rateHt40_0, rateHt40_1, rateHt40_2, rateHt40_3,
+ rateHt40_4, rateHt40_5, rateHt40_6, rateHt40_7,
+ rateDupCck, rateDupOfdm, rateExtCck, rateExtOfdm,
+ Ar5416RateSize
+};
+
+struct base_eep_header {
+ u16 length;
+ u16 checksum;
+ u16 version;
+ u8 opCapFlags;
+ u8 eepMisc;
+ u16 regDmn[2];
+ u8 macAddr[6];
+ u8 rxMask;
+ u8 txMask;
+ u16 rfSilent;
+ u16 blueToothOptions;
+ u16 deviceCap;
+ u32 binBuildNumber;
+ u8 deviceType;
+ u8 pwdclkind;
+ u8 futureBase[32];
+} __packed;
+
+struct spur_chan {
+ u16 spurChan;
+ u8 spurRangeLow;
+ u8 spurRangeHigh;
+} __packed;
+
+struct modal_eep_header {
+ u32 antCtrlChain[AR5416_MAX_CHAINS];
+ u32 antCtrlCommon;
+ u8 antennaGainCh[AR5416_MAX_CHAINS];
+ u8 switchSettling;
+ u8 txRxAttenCh[AR5416_MAX_CHAINS];
+ u8 rxTxMarginCh[AR5416_MAX_CHAINS];
+ u8 adcDesiredSize;
+ u8 pgaDesiredSize;
+ u8 xlnaGainCh[AR5416_MAX_CHAINS];
+ u8 txEndToXpaOff;
+ u8 txEndToRxOn;
+ u8 txFrameToXpaOn;
+ u8 thresh62;
+ u8 noiseFloorThreshCh[AR5416_MAX_CHAINS];
+ u8 xpdGain;
+ u8 xpd;
+ u8 iqCalICh[AR5416_MAX_CHAINS];
+ u8 iqCalQCh[AR5416_MAX_CHAINS];
+ u8 pdGainOverlap;
+ u8 ob;
+ u8 db;
+ u8 xpaBiasLvl;
+ u8 pwrDecreaseFor2Chain;
+ u8 pwrDecreaseFor3Chain;
+ u8 txFrameToDataStart;
+ u8 txFrameToPaOn;
+ u8 ht40PowerIncForPdadc;
+ u8 bswAtten[AR5416_MAX_CHAINS];
+ u8 bswMargin[AR5416_MAX_CHAINS];
+ u8 swSettleHt40;
+ u8 xatten2Db[AR5416_MAX_CHAINS];
+ u8 xatten2Margin[AR5416_MAX_CHAINS];
+ u8 ob_ch1;
+ u8 db_ch1;
+ u8 useAnt1:1,
+ force_xpaon:1,
+ local_bias:1,
+ femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1;
+ u8 futureModalar9280;
+ u16 xpaBiasLvlFreq[3];
+ u8 futureModal[6];
+
+ struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
+} __packed;
+
+struct cal_data_per_freq {
+ u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
+ u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
+} __packed;
+
+struct cal_target_power_leg {
+ u8 bChannel;
+ u8 tPow2x[4];
+} __packed;
+
+struct cal_target_power_ht {
+ u8 bChannel;
+ u8 tPow2x[8];
+} __packed;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+struct cal_ctl_edges {
+ u8 bChannel;
+ u8 flag:2, tPower:6;
+} __packed;
+#else
+struct cal_ctl_edges {
+ u8 bChannel;
+ u8 tPower:6, flag:2;
+} __packed;
+#endif
+
+struct cal_ctl_data {
+ struct cal_ctl_edges
+ ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
+} __packed;
+
+struct ar5416_eeprom {
+ struct base_eep_header baseEepHeader;
+ u8 custData[64];
+ struct modal_eep_header modalHeader[2];
+ u8 calFreqPier5G[AR5416_NUM_5G_CAL_PIERS];
+ u8 calFreqPier2G[AR5416_NUM_2G_CAL_PIERS];
+ struct cal_data_per_freq
+ calPierData5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS];
+ struct cal_data_per_freq
+ calPierData2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS];
+ struct cal_target_power_leg
+ calTargetPower5G[AR5416_NUM_5G_20_TARGET_POWERS];
+ struct cal_target_power_ht
+ calTargetPower5GHT20[AR5416_NUM_5G_20_TARGET_POWERS];
+ struct cal_target_power_ht
+ calTargetPower5GHT40[AR5416_NUM_5G_40_TARGET_POWERS];
+ struct cal_target_power_leg
+ calTargetPowerCck[AR5416_NUM_2G_CCK_TARGET_POWERS];
+ struct cal_target_power_leg
+ calTargetPower2G[AR5416_NUM_2G_20_TARGET_POWERS];
+ struct cal_target_power_ht
+ calTargetPower2GHT20[AR5416_NUM_2G_20_TARGET_POWERS];
+ struct cal_target_power_ht
+ calTargetPower2GHT40[AR5416_NUM_2G_40_TARGET_POWERS];
+ u8 ctlIndex[AR5416_NUM_CTLS];
+ struct cal_ctl_data ctlData[AR5416_NUM_CTLS];
+ u8 padding;
+} __packed;
+
+struct ar5416IniArray {
+ u32 *ia_array;
+ u32 ia_rows;
+ u32 ia_columns;
+};
+
+#define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \
+ (iniarray)->ia_array = (u32 *)(array); \
+ (iniarray)->ia_rows = (rows); \
+ (iniarray)->ia_columns = (columns); \
+ } while (0)
+
+#define INI_RA(iniarray, row, column) \
+ (((iniarray)->ia_array)[(row) * ((iniarray)->ia_columns) + (column)])
+
+#define INIT_CAL(_perCal) do { \
+ (_perCal)->calState = CAL_WAITING; \
+ (_perCal)->calNext = NULL; \
+ } while (0)
+
+#define INSERT_CAL(_ahp, _perCal) \
+ do { \
+ if ((_ahp)->ah_cal_list_last == NULL) { \
+ (_ahp)->ah_cal_list = \
+ (_ahp)->ah_cal_list_last = (_perCal); \
+ ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \
+ } else { \
+ ((_ahp)->ah_cal_list_last)->calNext = (_perCal); \
+ (_ahp)->ah_cal_list_last = (_perCal); \
+ (_perCal)->calNext = (_ahp)->ah_cal_list; \
+ } \
+ } while (0)
+
+enum hal_cal_types {
+ ADC_DC_INIT_CAL = 0x1,
+ ADC_GAIN_CAL = 0x2,
+ ADC_DC_CAL = 0x4,
+ IQ_MISMATCH_CAL = 0x8
+};
+
+enum hal_cal_state {
+ CAL_INACTIVE,
+ CAL_WAITING,
+ CAL_RUNNING,
+ CAL_DONE
+};
+
+#define MIN_CAL_SAMPLES 1
+#define MAX_CAL_SAMPLES 64
+#define INIT_LOG_COUNT 5
+#define PER_MIN_LOG_COUNT 2
+#define PER_MAX_LOG_COUNT 10
+
+struct hal_percal_data {
+ enum hal_cal_types calType;
+ u32 calNumSamples;
+ u32 calCountMax;
+ void (*calCollect) (struct ath_hal *);
+ void (*calPostProc) (struct ath_hal *, u8);
+};
+
+struct hal_cal_list {
+ const struct hal_percal_data *calData;
+ enum hal_cal_state calState;
+ struct hal_cal_list *calNext;
+};
+
+struct ath_hal_5416 {
+ struct ath_hal ah;
+ struct ar5416_eeprom ah_eeprom;
+ u8 ah_macaddr[ETH_ALEN];
+ u8 ah_bssid[ETH_ALEN];
+ u8 ah_bssidmask[ETH_ALEN];
+ u16 ah_assocId;
+ int16_t ah_curchanRadIndex;
+ u32 ah_maskReg;
+ struct ar5416Stats ah_stats;
+ u32 ah_txDescMask;
+ u32 ah_txOkInterruptMask;
+ u32 ah_txErrInterruptMask;
+ u32 ah_txDescInterruptMask;
+ u32 ah_txEolInterruptMask;
+ u32 ah_txUrnInterruptMask;
+ struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES];
+ enum ath9k_power_mode ah_powerMode;
+ bool ah_chipFullSleep;
+ u32 ah_atimWindow;
+ enum ath9k_ant_setting ah_diversityControl;
+ u16 ah_antennaSwitchSwap;
+ enum hal_cal_types ah_suppCals;
+ struct hal_cal_list ah_iqCalData;
+ struct hal_cal_list ah_adcGainCalData;
+ struct hal_cal_list ah_adcDcCalInitData;
+ struct hal_cal_list ah_adcDcCalData;
+ struct hal_cal_list *ah_cal_list;
+ struct hal_cal_list *ah_cal_list_last;
+ struct hal_cal_list *ah_cal_list_curr;
+#define ah_totalPowerMeasI ah_Meas0.unsign
+#define ah_totalPowerMeasQ ah_Meas1.unsign
+#define ah_totalIqCorrMeas ah_Meas2.sign
+#define ah_totalAdcIOddPhase ah_Meas0.unsign
+#define ah_totalAdcIEvenPhase ah_Meas1.unsign
+#define ah_totalAdcQOddPhase ah_Meas2.unsign
+#define ah_totalAdcQEvenPhase ah_Meas3.unsign
+#define ah_totalAdcDcOffsetIOddPhase ah_Meas0.sign
+#define ah_totalAdcDcOffsetIEvenPhase ah_Meas1.sign
+#define ah_totalAdcDcOffsetQOddPhase ah_Meas2.sign
+#define ah_totalAdcDcOffsetQEvenPhase ah_Meas3.sign
+ union {
+ u32 unsign[AR5416_MAX_CHAINS];
+ int32_t sign[AR5416_MAX_CHAINS];
+ } ah_Meas0;
+ union {
+ u32 unsign[AR5416_MAX_CHAINS];
+ int32_t sign[AR5416_MAX_CHAINS];
+ } ah_Meas1;
+ union {
+ u32 unsign[AR5416_MAX_CHAINS];
+ int32_t sign[AR5416_MAX_CHAINS];
+ } ah_Meas2;
+ union {
+ u32 unsign[AR5416_MAX_CHAINS];
+ int32_t sign[AR5416_MAX_CHAINS];
+ } ah_Meas3;
+ u16 ah_CalSamples;
+ u32 ah_tx6PowerInHalfDbm;
+ u32 ah_staId1Defaults;
+ u32 ah_miscMode;
+ bool ah_tpcEnabled;
+ u32 ah_beaconInterval;
+ enum {
+ AUTO_32KHZ,
+ USE_32KHZ,
+ DONT_USE_32KHZ,
+ } ah_enable32kHzClock;
+ u32 *ah_analogBank0Data;
+ u32 *ah_analogBank1Data;
+ u32 *ah_analogBank2Data;
+ u32 *ah_analogBank3Data;
+ u32 *ah_analogBank6Data;
+ u32 *ah_analogBank6TPCData;
+ u32 *ah_analogBank7Data;
+ u32 *ah_addac5416_21;
+ u32 *ah_bank6Temp;
+ u32 ah_ofdmTxPower;
+ int16_t ah_txPowerIndexOffset;
+ u32 ah_slottime;
+ u32 ah_acktimeout;
+ u32 ah_ctstimeout;
+ u32 ah_globaltxtimeout;
+ u8 ah_gBeaconRate;
+ u32 ah_gpioSelect;
+ u32 ah_polarity;
+ u32 ah_gpioBit;
+ bool ah_eepEnabled;
+ u32 ah_procPhyErr;
+ bool ah_hasHwPhyCounters;
+ u32 ah_aniPeriod;
+ struct ar5416AniState *ah_curani;
+ struct ar5416AniState ah_ani[255];
+ int ah_totalSizeDesired[5];
+ int ah_coarseHigh[5];
+ int ah_coarseLow[5];
+ int ah_firpwr[5];
+ u16 ah_ratesArray[16];
+ u32 ah_intrTxqs;
+ bool ah_intrMitigation;
+ u32 ah_cycleCount;
+ u32 ah_ctlBusy;
+ u32 ah_extBusy;
+ enum ath9k_ht_extprotspacing ah_extprotspacing;
+ u8 ah_txchainmask;
+ u8 ah_rxchainmask;
+ int ah_hwp;
+ void __iomem *ah_cal_mem;
+ enum ath9k_ani_cmd ah_ani_function;
+ struct ar5416IniArray ah_iniModes;
+ struct ar5416IniArray ah_iniCommon;
+ struct ar5416IniArray ah_iniBank0;
+ struct ar5416IniArray ah_iniBB_RfGain;
+ struct ar5416IniArray ah_iniBank1;
+ struct ar5416IniArray ah_iniBank2;
+ struct ar5416IniArray ah_iniBank3;
+ struct ar5416IniArray ah_iniBank6;
+ struct ar5416IniArray ah_iniBank6TPC;
+ struct ar5416IniArray ah_iniBank7;
+ struct ar5416IniArray ah_iniAddac;
+ struct ar5416IniArray ah_iniPcieSerdes;
+ struct ar5416IniArray ah_iniModesAdditional;
+};
+#define AH5416(_ah) ((struct ath_hal_5416 *)(_ah))
+
+#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5))
+
+#define IS_5416_EMU(ah) \
+ ((ah->ah_devid == AR5416_DEVID_EMU) || \
+ (ah->ah_devid == AR5416_DEVID_EMU_PCIE))
+
+#define ar5416RfDetach(ah) do { \
+ if (AH5416(ah)->ah_rfHal.rfDetach != NULL) \
+ AH5416(ah)->ah_rfHal.rfDetach(ah); \
+ } while (0)
+
+#define ath9k_hw_use_flash(_ah) \
+ (!(_ah->ah_flags & AH_USE_EEPROM))
+
+
+#define DO_DELAY(x) do { \
+ if ((++(x) % 64) == 0) \
+ udelay(1); \
+ } while (0)
+
+#define REG_WRITE_ARRAY(iniarray, column, regWr) do { \
+ int r; \
+ for (r = 0; r < ((iniarray)->ia_rows); r++) { \
+ REG_WRITE(ah, INI_RA((iniarray), (r), 0), \
+ INI_RA((iniarray), r, (column))); \
+ DO_DELAY(regWr); \
+ } \
+ } while (0)
+
+#define BASE_ACTIVATE_DELAY 100
+#define RTC_PLL_SETTLE_DELAY 1000
+#define COEF_SCALE_S 24
+#define HT40_CHANNEL_CENTER_SHIFT 10
+
+#define ar5416CheckOpMode(_opmode) \
+ ((_opmode == ATH9K_M_STA) || (_opmode == ATH9K_M_IBSS) || \
+ (_opmode == ATH9K_M_HOSTAP) || (_opmode == ATH9K_M_MONITOR))
+
+#define AR5416_EEPROM_MAGIC_OFFSET 0x0
+
+#define AR5416_EEPROM_S 2
+#define AR5416_EEPROM_OFFSET 0x2000
+#define AR5416_EEPROM_START_ADDR \
+ (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200
+#define AR5416_EEPROM_MAX 0xae0
+#define ar5416_get_eep_ver(_ahp) \
+ (((_ahp)->ah_eeprom.baseEepHeader.version >> 12) & 0xF)
+#define ar5416_get_eep_rev(_ahp) \
+ (((_ahp)->ah_eeprom.baseEepHeader.version) & 0xFFF)
+#define ar5416_get_ntxchains(_txchainmask) \
+ (((_txchainmask >> 2) & 1) + \
+ ((_txchainmask >> 1) & 1) + (_txchainmask & 1))
+
+#define IS_EEP_MINOR_V3(_ahp) \
+ (ath9k_hw_get_eeprom((_ahp), EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_3)
+
+#define FIXED_CCA_THRESHOLD 15
+
+#ifdef __BIG_ENDIAN
+#define AR5416_EEPROM_MAGIC 0x5aa5
+#else
+#define AR5416_EEPROM_MAGIC 0xa55a
+#endif
+
+#define ATH9K_POW_SM(_r, _s) (((_r) & 0x3f) << (_s))
+
+#define ATH9K_ANTENNA0_CHAINMASK 0x1
+#define ATH9K_ANTENNA1_CHAINMASK 0x2
+
+#define ATH9K_NUM_DMA_DEBUG_REGS 8
+#define ATH9K_NUM_QUEUES 10
+
+#define HAL_NOISE_IMMUNE_MAX 4
+#define HAL_SPUR_IMMUNE_MAX 7
+#define HAL_FIRST_STEP_MAX 2
+
+#define ATH9K_ANI_OFDM_TRIG_HIGH 500
+#define ATH9K_ANI_OFDM_TRIG_LOW 200
+#define ATH9K_ANI_CCK_TRIG_HIGH 200
+#define ATH9K_ANI_CCK_TRIG_LOW 100
+#define ATH9K_ANI_NOISE_IMMUNE_LVL 4
+#define ATH9K_ANI_USE_OFDM_WEAK_SIG true
+#define ATH9K_ANI_CCK_WEAK_SIG_THR false
+#define ATH9K_ANI_SPUR_IMMUNE_LVL 7
+#define ATH9K_ANI_FIRSTEP_LVL 0
+#define ATH9K_ANI_RSSI_THR_HIGH 40
+#define ATH9K_ANI_RSSI_THR_LOW 7
+#define ATH9K_ANI_PERIOD 100
+
+#define AR_GPIOD_MASK 0x00001FFF
+#define AR_GPIO_BIT(_gpio) (1 << (_gpio))
+
+#define MAX_ANALOG_START 319
+
+#define HAL_EP_RND(x, mul) \
+ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+#define BEACON_RSSI(ahp) \
+ HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \
+ ATH9K_RSSI_EP_MULTIPLIER)
+
+#define ah_mibStats ah_stats.ast_mibstats
+
+#define AH_TIMEOUT 100000
+#define AH_TIME_QUANTUM 10
+
+#define IS(_c, _f) (((_c)->channelFlags & _f) || 0)
+
+#define AR_KEYTABLE_SIZE 128
+#define POWER_UP_TIME 200000
+
+#define EXT_ADDITIVE (0x8000)
+#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
+#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
+#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
+
+#define SUB_NUM_CTL_MODES_AT_5G_40 2
+#define SUB_NUM_CTL_MODES_AT_2G_40 3
+#define SPUR_RSSI_THRESH 40
+
+#define TU_TO_USEC(_tu) ((_tu) << 10)
+
+#define CAB_TIMEOUT_VAL 10
+#define BEACON_TIMEOUT_VAL 10
+#define MIN_BEACON_TIMEOUT_VAL 1
+#define SLEEP_SLOP 3
+
+#define CCK_SIFS_TIME 10
+#define CCK_PREAMBLE_BITS 144
+#define CCK_PLCP_BITS 48
+
+#define OFDM_SIFS_TIME 16
+#define OFDM_PREAMBLE_TIME 20
+#define OFDM_PLCP_BITS 22
+#define OFDM_SYMBOL_TIME 4
+
+#define OFDM_SIFS_TIME_HALF 32
+#define OFDM_PREAMBLE_TIME_HALF 40
+#define OFDM_PLCP_BITS_HALF 22
+#define OFDM_SYMBOL_TIME_HALF 8
+
+#define OFDM_SIFS_TIME_QUARTER 64
+#define OFDM_PREAMBLE_TIME_QUARTER 80
+#define OFDM_PLCP_BITS_QUARTER 22
+#define OFDM_SYMBOL_TIME_QUARTER 16
+
+u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp,
+ enum eeprom_param param);
+
+#endif
diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h
new file mode 100644
index 00000000000..3dd3815940a
--- /dev/null
+++ b/drivers/net/wireless/ath9k/initvals.h
@@ -0,0 +1,3146 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+static const u32 ar5416Modes_9100[][6] = {
+ { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
+ { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+ { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
+ { 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 },
+ { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 },
+ { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+ { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+ { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+ { 0x00009850, 0x6de8b4e0, 0x6de8b4e0, 0x6de8b0de, 0x6de8b0de, 0x6de8b0de },
+ { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
+ { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+ { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
+ { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
+ { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
+ { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 },
+ { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b },
+ { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+ { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
+ { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
+ { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
+ { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 },
+ { 0x0000c9bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 },
+ { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
+ { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+ { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c },
+ { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+ { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+ { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
+ { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
+ { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
+ { 0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
+ { 0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
+ { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
+ { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
+ { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
+ { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
+ { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
+ { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
+ { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
+ { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
+ { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
+ { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
+ { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
+ { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+};
+
+static const u32 ar5416Common_9100[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020015 },
+ { 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 },
+ { 0x00007010, 0x00000000 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x40000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x00000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x000080c0, 0x2a82301a },
+ { 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, 0x08f04800 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0x00000000 },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x32143320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c4, 0x00000000 },
+ { 0x000081d0, 0x00003210 },
+ { 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 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x00000000 },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x00008300, 0x00000000 },
+ { 0x00008304, 0x00000000 },
+ { 0x00008308, 0x00000000 },
+ { 0x0000830c, 0x00000000 },
+ { 0x00008310, 0x00000000 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008318, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000007 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00000000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x000107ff },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xad848e19 },
+ { 0x00009810, 0x7d14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x00009840, 0x206a002e },
+ { 0x0000984c, 0x1284233c },
+ { 0x00009854, 0x00000859 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x05100000 },
+ { 0x0000a920, 0x05100000 },
+ { 0x0000b920, 0x05100000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009948, 0x9280b212 },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0x5d50e188 },
+ { 0x00009958, 0x00081fff },
+ { 0x0000c95c, 0x004b6a8e },
+ { 0x0000c968, 0x000003ce },
+ { 0x00009970, 0x190fb515 },
+ { 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, 0x001fff00 },
+ { 0x000099ac, 0x00000000 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000200 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x000000aa },
+ { 0x000099fc, 0x00001042 },
+ { 0x00009b00, 0x00000000 },
+ { 0x00009b04, 0x00000001 },
+ { 0x00009b08, 0x00000002 },
+ { 0x00009b0c, 0x00000003 },
+ { 0x00009b10, 0x00000004 },
+ { 0x00009b14, 0x00000005 },
+ { 0x00009b18, 0x00000008 },
+ { 0x00009b1c, 0x00000009 },
+ { 0x00009b20, 0x0000000a },
+ { 0x00009b24, 0x0000000b },
+ { 0x00009b28, 0x0000000c },
+ { 0x00009b2c, 0x0000000d },
+ { 0x00009b30, 0x00000010 },
+ { 0x00009b34, 0x00000011 },
+ { 0x00009b38, 0x00000012 },
+ { 0x00009b3c, 0x00000013 },
+ { 0x00009b40, 0x00000014 },
+ { 0x00009b44, 0x00000015 },
+ { 0x00009b48, 0x00000018 },
+ { 0x00009b4c, 0x00000019 },
+ { 0x00009b50, 0x0000001a },
+ { 0x00009b54, 0x0000001b },
+ { 0x00009b58, 0x0000001c },
+ { 0x00009b5c, 0x0000001d },
+ { 0x00009b60, 0x00000020 },
+ { 0x00009b64, 0x00000021 },
+ { 0x00009b68, 0x00000022 },
+ { 0x00009b6c, 0x00000023 },
+ { 0x00009b70, 0x00000024 },
+ { 0x00009b74, 0x00000025 },
+ { 0x00009b78, 0x00000028 },
+ { 0x00009b7c, 0x00000029 },
+ { 0x00009b80, 0x0000002a },
+ { 0x00009b84, 0x0000002b },
+ { 0x00009b88, 0x0000002c },
+ { 0x00009b8c, 0x0000002d },
+ { 0x00009b90, 0x00000030 },
+ { 0x00009b94, 0x00000031 },
+ { 0x00009b98, 0x00000032 },
+ { 0x00009b9c, 0x00000033 },
+ { 0x00009ba0, 0x00000034 },
+ { 0x00009ba4, 0x00000035 },
+ { 0x00009ba8, 0x00000035 },
+ { 0x00009bac, 0x00000035 },
+ { 0x00009bb0, 0x00000035 },
+ { 0x00009bb4, 0x00000035 },
+ { 0x00009bb8, 0x00000035 },
+ { 0x00009bbc, 0x00000035 },
+ { 0x00009bc0, 0x00000035 },
+ { 0x00009bc4, 0x00000035 },
+ { 0x00009bc8, 0x00000035 },
+ { 0x00009bcc, 0x00000035 },
+ { 0x00009bd0, 0x00000035 },
+ { 0x00009bd4, 0x00000035 },
+ { 0x00009bd8, 0x00000035 },
+ { 0x00009bdc, 0x00000035 },
+ { 0x00009be0, 0x00000035 },
+ { 0x00009be4, 0x00000035 },
+ { 0x00009be8, 0x00000035 },
+ { 0x00009bec, 0x00000035 },
+ { 0x00009bf0, 0x00000035 },
+ { 0x00009bf4, 0x00000035 },
+ { 0x00009bf8, 0x00000010 },
+ { 0x00009bfc, 0x0000001a },
+ { 0x0000a210, 0x40806333 },
+ { 0x0000a214, 0x00106c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x018830c6 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x00000bb5 },
+ { 0x0000a22c, 0x00000011 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a23c, 0x13c889af },
+ { 0x0000a240, 0x38490a20 },
+ { 0x0000a244, 0x00007bb6 },
+ { 0x0000a248, 0x0fff3ffc },
+ { 0x0000a24c, 0x00000001 },
+ { 0x0000a250, 0x0000a000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0cc75380 },
+ { 0x0000a25c, 0x0f0f0f01 },
+ { 0x0000a260, 0xdfa91f01 },
+ { 0x0000a268, 0x00000000 },
+ { 0x0000a26c, 0x0ebae9c6 },
+ { 0x0000b26c, 0x0ebae9c6 },
+ { 0x0000c26c, 0x0ebae9c6 },
+ { 0x0000d270, 0x00820820 },
+ { 0x0000a278, 0x1ce739ce },
+ { 0x0000a27c, 0x051701ce },
+ { 0x0000a338, 0x00000000 },
+ { 0x0000a33c, 0x00000000 },
+ { 0x0000a340, 0x00000000 },
+ { 0x0000a344, 0x00000000 },
+ { 0x0000a348, 0x3fffffff },
+ { 0x0000a34c, 0x3fffffff },
+ { 0x0000a350, 0x3fffffff },
+ { 0x0000a354, 0x0003ffff },
+ { 0x0000a358, 0x79a8aa1f },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+ { 0x0000a388, 0x08000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x1ce739ce },
+ { 0x0000a398, 0x000001ce },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3a0, 0x00000000 },
+ { 0x0000a3a4, 0x00000000 },
+ { 0x0000a3a8, 0x00000000 },
+ { 0x0000a3ac, 0x00000000 },
+ { 0x0000a3b0, 0x00000000 },
+ { 0x0000a3b4, 0x00000000 },
+ { 0x0000a3b8, 0x00000000 },
+ { 0x0000a3bc, 0x00000000 },
+ { 0x0000a3c0, 0x00000000 },
+ { 0x0000a3c4, 0x00000000 },
+ { 0x0000a3c8, 0x00000246 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x1ce739ce },
+ { 0x0000a3e0, 0x000001ce },
+};
+
+static const u32 ar5416Bank0_9100[][2] = {
+ { 0x000098b0, 0x1e5795e5 },
+ { 0x000098e0, 0x02008020 },
+};
+
+static const u32 ar5416BB_RfGain_9100[][3] = {
+ { 0x00009a00, 0x00000000, 0x00000000 },
+ { 0x00009a04, 0x00000040, 0x00000040 },
+ { 0x00009a08, 0x00000080, 0x00000080 },
+ { 0x00009a0c, 0x000001a1, 0x00000141 },
+ { 0x00009a10, 0x000001e1, 0x00000181 },
+ { 0x00009a14, 0x00000021, 0x000001c1 },
+ { 0x00009a18, 0x00000061, 0x00000001 },
+ { 0x00009a1c, 0x00000168, 0x00000041 },
+ { 0x00009a20, 0x000001a8, 0x000001a8 },
+ { 0x00009a24, 0x000001e8, 0x000001e8 },
+ { 0x00009a28, 0x00000028, 0x00000028 },
+ { 0x00009a2c, 0x00000068, 0x00000068 },
+ { 0x00009a30, 0x00000189, 0x000000a8 },
+ { 0x00009a34, 0x000001c9, 0x00000169 },
+ { 0x00009a38, 0x00000009, 0x000001a9 },
+ { 0x00009a3c, 0x00000049, 0x000001e9 },
+ { 0x00009a40, 0x00000089, 0x00000029 },
+ { 0x00009a44, 0x00000170, 0x00000069 },
+ { 0x00009a48, 0x000001b0, 0x00000190 },
+ { 0x00009a4c, 0x000001f0, 0x000001d0 },
+ { 0x00009a50, 0x00000030, 0x00000010 },
+ { 0x00009a54, 0x00000070, 0x00000050 },
+ { 0x00009a58, 0x00000191, 0x00000090 },
+ { 0x00009a5c, 0x000001d1, 0x00000151 },
+ { 0x00009a60, 0x00000011, 0x00000191 },
+ { 0x00009a64, 0x00000051, 0x000001d1 },
+ { 0x00009a68, 0x00000091, 0x00000011 },
+ { 0x00009a6c, 0x000001b8, 0x00000051 },
+ { 0x00009a70, 0x000001f8, 0x00000198 },
+ { 0x00009a74, 0x00000038, 0x000001d8 },
+ { 0x00009a78, 0x00000078, 0x00000018 },
+ { 0x00009a7c, 0x00000199, 0x00000058 },
+ { 0x00009a80, 0x000001d9, 0x00000098 },
+ { 0x00009a84, 0x00000019, 0x00000159 },
+ { 0x00009a88, 0x00000059, 0x00000199 },
+ { 0x00009a8c, 0x00000099, 0x000001d9 },
+ { 0x00009a90, 0x000000d9, 0x00000019 },
+ { 0x00009a94, 0x000000f9, 0x00000059 },
+ { 0x00009a98, 0x000000f9, 0x00000099 },
+ { 0x00009a9c, 0x000000f9, 0x000000d9 },
+ { 0x00009aa0, 0x000000f9, 0x000000f9 },
+ { 0x00009aa4, 0x000000f9, 0x000000f9 },
+ { 0x00009aa8, 0x000000f9, 0x000000f9 },
+ { 0x00009aac, 0x000000f9, 0x000000f9 },
+ { 0x00009ab0, 0x000000f9, 0x000000f9 },
+ { 0x00009ab4, 0x000000f9, 0x000000f9 },
+ { 0x00009ab8, 0x000000f9, 0x000000f9 },
+ { 0x00009abc, 0x000000f9, 0x000000f9 },
+ { 0x00009ac0, 0x000000f9, 0x000000f9 },
+ { 0x00009ac4, 0x000000f9, 0x000000f9 },
+ { 0x00009ac8, 0x000000f9, 0x000000f9 },
+ { 0x00009acc, 0x000000f9, 0x000000f9 },
+ { 0x00009ad0, 0x000000f9, 0x000000f9 },
+ { 0x00009ad4, 0x000000f9, 0x000000f9 },
+ { 0x00009ad8, 0x000000f9, 0x000000f9 },
+ { 0x00009adc, 0x000000f9, 0x000000f9 },
+ { 0x00009ae0, 0x000000f9, 0x000000f9 },
+ { 0x00009ae4, 0x000000f9, 0x000000f9 },
+ { 0x00009ae8, 0x000000f9, 0x000000f9 },
+ { 0x00009aec, 0x000000f9, 0x000000f9 },
+ { 0x00009af0, 0x000000f9, 0x000000f9 },
+ { 0x00009af4, 0x000000f9, 0x000000f9 },
+ { 0x00009af8, 0x000000f9, 0x000000f9 },
+ { 0x00009afc, 0x000000f9, 0x000000f9 },
+};
+
+static const u32 ar5416Bank1_9100[][2] = {
+ { 0x000098b0, 0x02108421 },
+ { 0x000098ec, 0x00000008 },
+};
+
+static const u32 ar5416Bank2_9100[][2] = {
+ { 0x000098b0, 0x0e73ff17 },
+ { 0x000098e0, 0x00000420 },
+};
+
+static const u32 ar5416Bank3_9100[][3] = {
+ { 0x000098f0, 0x01400018, 0x01c00018 },
+};
+
+static const u32 ar5416Bank6_9100[][3] = {
+
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00e00000, 0x00e00000 },
+ { 0x0000989c, 0x005e0000, 0x005e0000 },
+ { 0x0000989c, 0x00120000, 0x00120000 },
+ { 0x0000989c, 0x00620000, 0x00620000 },
+ { 0x0000989c, 0x00020000, 0x00020000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x40ff0000, 0x40ff0000 },
+ { 0x0000989c, 0x005f0000, 0x005f0000 },
+ { 0x0000989c, 0x00870000, 0x00870000 },
+ { 0x0000989c, 0x00f90000, 0x00f90000 },
+ { 0x0000989c, 0x007b0000, 0x007b0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00f50000, 0x00f50000 },
+ { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+ { 0x0000989c, 0x00110000, 0x00110000 },
+ { 0x0000989c, 0x006100a8, 0x006100a8 },
+ { 0x0000989c, 0x004210a2, 0x004210a2 },
+ { 0x0000989c, 0x0014008f, 0x0014008f },
+ { 0x0000989c, 0x00c40003, 0x00c40003 },
+ { 0x0000989c, 0x003000f2, 0x003000f2 },
+ { 0x0000989c, 0x00440016, 0x00440016 },
+ { 0x0000989c, 0x00410040, 0x00410040 },
+ { 0x0000989c, 0x0001805e, 0x0001805e },
+ { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
+ { 0x0000989c, 0x000000f1, 0x000000f1 },
+ { 0x0000989c, 0x00002081, 0x00002081 },
+ { 0x0000989c, 0x000000d4, 0x000000d4 },
+ { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+static const u32 ar5416Bank6TPC_9100[][3] = {
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00e00000, 0x00e00000 },
+ { 0x0000989c, 0x005e0000, 0x005e0000 },
+ { 0x0000989c, 0x00120000, 0x00120000 },
+ { 0x0000989c, 0x00620000, 0x00620000 },
+ { 0x0000989c, 0x00020000, 0x00020000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x40ff0000, 0x40ff0000 },
+ { 0x0000989c, 0x005f0000, 0x005f0000 },
+ { 0x0000989c, 0x00870000, 0x00870000 },
+ { 0x0000989c, 0x00f90000, 0x00f90000 },
+ { 0x0000989c, 0x007b0000, 0x007b0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00f50000, 0x00f50000 },
+ { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+ { 0x0000989c, 0x00110000, 0x00110000 },
+ { 0x0000989c, 0x006100a8, 0x006100a8 },
+ { 0x0000989c, 0x00423022, 0x00423022 },
+ { 0x0000989c, 0x201400df, 0x201400df },
+ { 0x0000989c, 0x00c40002, 0x00c40002 },
+ { 0x0000989c, 0x003000f2, 0x003000f2 },
+ { 0x0000989c, 0x00440016, 0x00440016 },
+ { 0x0000989c, 0x00410040, 0x00410040 },
+ { 0x0000989c, 0x0001805e, 0x0001805e },
+ { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
+ { 0x0000989c, 0x000000e1, 0x000000e1 },
+ { 0x0000989c, 0x00007081, 0x00007081 },
+ { 0x0000989c, 0x000000d4, 0x000000d4 },
+ { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+static const u32 ar5416Bank7_9100[][2] = {
+ { 0x0000989c, 0x00000500 },
+ { 0x0000989c, 0x00000800 },
+ { 0x000098cc, 0x0000000e },
+};
+
+static const u32 ar5416Addac_9100[][2] = {
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000003 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x0000000c },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000030 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000060 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000058 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x000098c4, 0x00000000 },
+};
+
+static const u32 ar5416Modes[][6] = {
+ { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
+ { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+ { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
+ { 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 },
+ { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
+ { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+ { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+ { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+ { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 },
+ { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec86d2e, 0x7ec84d2e, 0x7ec82d2e },
+ { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+ { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
+ { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
+ { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
+ { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a11, 0xd00a8a0d, 0xd00a8a0d },
+ { 0x00009940, 0x00754604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204 },
+ { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+ { 0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e },
+ { 0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff },
+#ifdef TB243
+ { 0x00009960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
+ { 0x0000a960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
+ { 0x0000b960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
+ { 0x00009964, 0x00000000, 0x00000000, 0x00002210, 0x00002210, 0x00001120 },
+#else
+ { 0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
+ { 0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
+ { 0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
+ { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
+#endif
+ { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00 },
+ { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
+ { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+ { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
+ { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+ { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+ { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
+ { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
+ { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+ { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+ { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+ { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
+ { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
+ { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
+ { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
+ { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
+ { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
+ { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
+ { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
+ { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
+ { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
+ { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
+ { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+};
+
+static const u32 ar5416Common[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020015 },
+ { 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 },
+ { 0x00020010, 0x00000003 },
+ { 0x00020038, 0x000004c2 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x40000000 },
+ { 0x00008054, 0x00004000 },
+ { 0x00008058, 0x00000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x000080c0, 0x2a82301a },
+ { 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, 0x08f04800 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0x00000000 },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x32143320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c4, 0x00000000 },
+ { 0x000081d0, 0x00003210 },
+ { 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 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x00000000 },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x00008300, 0x00000000 },
+ { 0x00008304, 0x00000000 },
+ { 0x00008308, 0x00000000 },
+ { 0x0000830c, 0x00000000 },
+ { 0x00008310, 0x00000000 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008318, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000007 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00000000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x000107ff },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xad848e19 },
+ { 0x00009810, 0x7d14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x00009840, 0x206a01ae },
+ { 0x0000984c, 0x1284233c },
+ { 0x00009854, 0x00000859 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x05100000 },
+ { 0x0000a920, 0x05100000 },
+ { 0x0000b920, 0x05100000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009948, 0x9280b212 },
+ { 0x0000994c, 0x00020028 },
+ { 0x0000c95c, 0x004b6a8e },
+ { 0x0000c968, 0x000003ce },
+ { 0x00009970, 0x190fb514 },
+ { 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, 0x006f0000 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000200 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099fc, 0x00001042 },
+ { 0x00009b00, 0x00000000 },
+ { 0x00009b04, 0x00000001 },
+ { 0x00009b08, 0x00000002 },
+ { 0x00009b0c, 0x00000003 },
+ { 0x00009b10, 0x00000004 },
+ { 0x00009b14, 0x00000005 },
+ { 0x00009b18, 0x00000008 },
+ { 0x00009b1c, 0x00000009 },
+ { 0x00009b20, 0x0000000a },
+ { 0x00009b24, 0x0000000b },
+ { 0x00009b28, 0x0000000c },
+ { 0x00009b2c, 0x0000000d },
+ { 0x00009b30, 0x00000010 },
+ { 0x00009b34, 0x00000011 },
+ { 0x00009b38, 0x00000012 },
+ { 0x00009b3c, 0x00000013 },
+ { 0x00009b40, 0x00000014 },
+ { 0x00009b44, 0x00000015 },
+ { 0x00009b48, 0x00000018 },
+ { 0x00009b4c, 0x00000019 },
+ { 0x00009b50, 0x0000001a },
+ { 0x00009b54, 0x0000001b },
+ { 0x00009b58, 0x0000001c },
+ { 0x00009b5c, 0x0000001d },
+ { 0x00009b60, 0x00000020 },
+ { 0x00009b64, 0x00000021 },
+ { 0x00009b68, 0x00000022 },
+ { 0x00009b6c, 0x00000023 },
+ { 0x00009b70, 0x00000024 },
+ { 0x00009b74, 0x00000025 },
+ { 0x00009b78, 0x00000028 },
+ { 0x00009b7c, 0x00000029 },
+ { 0x00009b80, 0x0000002a },
+ { 0x00009b84, 0x0000002b },
+ { 0x00009b88, 0x0000002c },
+ { 0x00009b8c, 0x0000002d },
+ { 0x00009b90, 0x00000030 },
+ { 0x00009b94, 0x00000031 },
+ { 0x00009b98, 0x00000032 },
+ { 0x00009b9c, 0x00000033 },
+ { 0x00009ba0, 0x00000034 },
+ { 0x00009ba4, 0x00000035 },
+ { 0x00009ba8, 0x00000035 },
+ { 0x00009bac, 0x00000035 },
+ { 0x00009bb0, 0x00000035 },
+ { 0x00009bb4, 0x00000035 },
+ { 0x00009bb8, 0x00000035 },
+ { 0x00009bbc, 0x00000035 },
+ { 0x00009bc0, 0x00000035 },
+ { 0x00009bc4, 0x00000035 },
+ { 0x00009bc8, 0x00000035 },
+ { 0x00009bcc, 0x00000035 },
+ { 0x00009bd0, 0x00000035 },
+ { 0x00009bd4, 0x00000035 },
+ { 0x00009bd8, 0x00000035 },
+ { 0x00009bdc, 0x00000035 },
+ { 0x00009be0, 0x00000035 },
+ { 0x00009be4, 0x00000035 },
+ { 0x00009be8, 0x00000035 },
+ { 0x00009bec, 0x00000035 },
+ { 0x00009bf0, 0x00000035 },
+ { 0x00009bf4, 0x00000035 },
+ { 0x00009bf8, 0x00000010 },
+ { 0x00009bfc, 0x0000001a },
+ { 0x0000a210, 0x40806333 },
+ { 0x0000a214, 0x00106c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x018830c6 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x001a0bb5 },
+ { 0x0000a22c, 0x00000000 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a23c, 0x13c889ae },
+ { 0x0000a240, 0x38490a20 },
+ { 0x0000a244, 0x00007bb6 },
+ { 0x0000a248, 0x0fff3ffc },
+ { 0x0000a24c, 0x00000001 },
+ { 0x0000a250, 0x0000a000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0cc75380 },
+ { 0x0000a25c, 0x0f0f0f01 },
+ { 0x0000a260, 0xdfa91f01 },
+ { 0x0000a268, 0x00000001 },
+ { 0x0000a26c, 0x0ebae9c6 },
+ { 0x0000b26c, 0x0ebae9c6 },
+ { 0x0000c26c, 0x0ebae9c6 },
+ { 0x0000d270, 0x00820820 },
+ { 0x0000a278, 0x1ce739ce },
+ { 0x0000a27c, 0x050701ce },
+ { 0x0000a338, 0x00000000 },
+ { 0x0000a33c, 0x00000000 },
+ { 0x0000a340, 0x00000000 },
+ { 0x0000a344, 0x00000000 },
+ { 0x0000a348, 0x3fffffff },
+ { 0x0000a34c, 0x3fffffff },
+ { 0x0000a350, 0x3fffffff },
+ { 0x0000a354, 0x0003ffff },
+ { 0x0000a358, 0x79a8aa33 },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x1ce739ce },
+ { 0x0000a398, 0x000001ce },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3a0, 0x00000000 },
+ { 0x0000a3a4, 0x00000000 },
+ { 0x0000a3a8, 0x00000000 },
+ { 0x0000a3ac, 0x00000000 },
+ { 0x0000a3b0, 0x00000000 },
+ { 0x0000a3b4, 0x00000000 },
+ { 0x0000a3b8, 0x00000000 },
+ { 0x0000a3bc, 0x00000000 },
+ { 0x0000a3c0, 0x00000000 },
+ { 0x0000a3c4, 0x00000000 },
+ { 0x0000a3c8, 0x00000246 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x1ce739ce },
+ { 0x0000a3e0, 0x000001ce },
+};
+
+static const u32 ar5416Bank0[][2] = {
+ { 0x000098b0, 0x1e5795e5 },
+ { 0x000098e0, 0x02008020 },
+};
+
+static const u32 ar5416BB_RfGain[][3] = {
+ { 0x00009a00, 0x00000000, 0x00000000 },
+ { 0x00009a04, 0x00000040, 0x00000040 },
+ { 0x00009a08, 0x00000080, 0x00000080 },
+ { 0x00009a0c, 0x000001a1, 0x00000141 },
+ { 0x00009a10, 0x000001e1, 0x00000181 },
+ { 0x00009a14, 0x00000021, 0x000001c1 },
+ { 0x00009a18, 0x00000061, 0x00000001 },
+ { 0x00009a1c, 0x00000168, 0x00000041 },
+ { 0x00009a20, 0x000001a8, 0x000001a8 },
+ { 0x00009a24, 0x000001e8, 0x000001e8 },
+ { 0x00009a28, 0x00000028, 0x00000028 },
+ { 0x00009a2c, 0x00000068, 0x00000068 },
+ { 0x00009a30, 0x00000189, 0x000000a8 },
+ { 0x00009a34, 0x000001c9, 0x00000169 },
+ { 0x00009a38, 0x00000009, 0x000001a9 },
+ { 0x00009a3c, 0x00000049, 0x000001e9 },
+ { 0x00009a40, 0x00000089, 0x00000029 },
+ { 0x00009a44, 0x00000170, 0x00000069 },
+ { 0x00009a48, 0x000001b0, 0x00000190 },
+ { 0x00009a4c, 0x000001f0, 0x000001d0 },
+ { 0x00009a50, 0x00000030, 0x00000010 },
+ { 0x00009a54, 0x00000070, 0x00000050 },
+ { 0x00009a58, 0x00000191, 0x00000090 },
+ { 0x00009a5c, 0x000001d1, 0x00000151 },
+ { 0x00009a60, 0x00000011, 0x00000191 },
+ { 0x00009a64, 0x00000051, 0x000001d1 },
+ { 0x00009a68, 0x00000091, 0x00000011 },
+ { 0x00009a6c, 0x000001b8, 0x00000051 },
+ { 0x00009a70, 0x000001f8, 0x00000198 },
+ { 0x00009a74, 0x00000038, 0x000001d8 },
+ { 0x00009a78, 0x00000078, 0x00000018 },
+ { 0x00009a7c, 0x00000199, 0x00000058 },
+ { 0x00009a80, 0x000001d9, 0x00000098 },
+ { 0x00009a84, 0x00000019, 0x00000159 },
+ { 0x00009a88, 0x00000059, 0x00000199 },
+ { 0x00009a8c, 0x00000099, 0x000001d9 },
+ { 0x00009a90, 0x000000d9, 0x00000019 },
+ { 0x00009a94, 0x000000f9, 0x00000059 },
+ { 0x00009a98, 0x000000f9, 0x00000099 },
+ { 0x00009a9c, 0x000000f9, 0x000000d9 },
+ { 0x00009aa0, 0x000000f9, 0x000000f9 },
+ { 0x00009aa4, 0x000000f9, 0x000000f9 },
+ { 0x00009aa8, 0x000000f9, 0x000000f9 },
+ { 0x00009aac, 0x000000f9, 0x000000f9 },
+ { 0x00009ab0, 0x000000f9, 0x000000f9 },
+ { 0x00009ab4, 0x000000f9, 0x000000f9 },
+ { 0x00009ab8, 0x000000f9, 0x000000f9 },
+ { 0x00009abc, 0x000000f9, 0x000000f9 },
+ { 0x00009ac0, 0x000000f9, 0x000000f9 },
+ { 0x00009ac4, 0x000000f9, 0x000000f9 },
+ { 0x00009ac8, 0x000000f9, 0x000000f9 },
+ { 0x00009acc, 0x000000f9, 0x000000f9 },
+ { 0x00009ad0, 0x000000f9, 0x000000f9 },
+ { 0x00009ad4, 0x000000f9, 0x000000f9 },
+ { 0x00009ad8, 0x000000f9, 0x000000f9 },
+ { 0x00009adc, 0x000000f9, 0x000000f9 },
+ { 0x00009ae0, 0x000000f9, 0x000000f9 },
+ { 0x00009ae4, 0x000000f9, 0x000000f9 },
+ { 0x00009ae8, 0x000000f9, 0x000000f9 },
+ { 0x00009aec, 0x000000f9, 0x000000f9 },
+ { 0x00009af0, 0x000000f9, 0x000000f9 },
+ { 0x00009af4, 0x000000f9, 0x000000f9 },
+ { 0x00009af8, 0x000000f9, 0x000000f9 },
+ { 0x00009afc, 0x000000f9, 0x000000f9 },
+};
+
+static const u32 ar5416Bank1[][2] = {
+ { 0x000098b0, 0x02108421},
+ { 0x000098ec, 0x00000008},
+};
+
+static const u32 ar5416Bank2[][2] = {
+ { 0x000098b0, 0x0e73ff17},
+ { 0x000098e0, 0x00000420},
+};
+
+static const u32 ar5416Bank3[][3] = {
+ { 0x000098f0, 0x01400018, 0x01c00018 },
+};
+
+static const u32 ar5416Bank6[][3] = {
+
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00e00000, 0x00e00000 },
+ { 0x0000989c, 0x005e0000, 0x005e0000 },
+ { 0x0000989c, 0x00120000, 0x00120000 },
+ { 0x0000989c, 0x00620000, 0x00620000 },
+ { 0x0000989c, 0x00020000, 0x00020000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x005f0000, 0x005f0000 },
+ { 0x0000989c, 0x00870000, 0x00870000 },
+ { 0x0000989c, 0x00f90000, 0x00f90000 },
+ { 0x0000989c, 0x007b0000, 0x007b0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00f50000, 0x00f50000 },
+ { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+ { 0x0000989c, 0x00110000, 0x00110000 },
+ { 0x0000989c, 0x006100a8, 0x006100a8 },
+ { 0x0000989c, 0x004210a2, 0x004210a2 },
+ { 0x0000989c, 0x0014000f, 0x0014000f },
+ { 0x0000989c, 0x00c40002, 0x00c40002 },
+ { 0x0000989c, 0x003000f2, 0x003000f2 },
+ { 0x0000989c, 0x00440016, 0x00440016 },
+ { 0x0000989c, 0x00410040, 0x00410040 },
+ { 0x0000989c, 0x000180d6, 0x000180d6 },
+ { 0x0000989c, 0x0000c0aa, 0x0000c0aa },
+ { 0x0000989c, 0x000000b1, 0x000000b1 },
+ { 0x0000989c, 0x00002000, 0x00002000 },
+ { 0x0000989c, 0x000000d4, 0x000000d4 },
+ { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+
+static const u32 ar5416Bank6TPC[][3] = {
+
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00e00000, 0x00e00000 },
+ { 0x0000989c, 0x005e0000, 0x005e0000 },
+ { 0x0000989c, 0x00120000, 0x00120000 },
+ { 0x0000989c, 0x00620000, 0x00620000 },
+ { 0x0000989c, 0x00020000, 0x00020000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x40ff0000, 0x40ff0000 },
+ { 0x0000989c, 0x005f0000, 0x005f0000 },
+ { 0x0000989c, 0x00870000, 0x00870000 },
+ { 0x0000989c, 0x00f90000, 0x00f90000 },
+ { 0x0000989c, 0x007b0000, 0x007b0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00f50000, 0x00f50000 },
+ { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+ { 0x0000989c, 0x00110000, 0x00110000 },
+ { 0x0000989c, 0x006100a8, 0x006100a8 },
+ { 0x0000989c, 0x00423022, 0x00423022 },
+ { 0x0000989c, 0x2014008f, 0x2014008f },
+ { 0x0000989c, 0x00c40002, 0x00c40002 },
+ { 0x0000989c, 0x003000f2, 0x003000f2 },
+ { 0x0000989c, 0x00440016, 0x00440016 },
+ { 0x0000989c, 0x00410040, 0x00410040 },
+ { 0x0000989c, 0x0001805e, 0x0001805e },
+ { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
+ { 0x0000989c, 0x000000e1, 0x000000e1 },
+ { 0x0000989c, 0x00007080, 0x00007080 },
+ { 0x0000989c, 0x000000d4, 0x000000d4 },
+ { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+static const u32 ar5416Bank7[][2] = {
+ { 0x0000989c, 0x00000500 },
+ { 0x0000989c, 0x00000800 },
+ { 0x000098cc, 0x0000000e },
+};
+
+static const u32 ar5416Addac[][2] = {
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000010 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x000000c0 },
+ {0x0000989c, 0x00000015 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x000098cc, 0x00000000 },
+};
+
+
+static const u32 ar5416Modes_9160[][6] = {
+ { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
+ { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+ { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
+ { 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 },
+ { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
+ { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+ { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+ { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+ { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 },
+ { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
+ { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+ { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
+ { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
+ { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
+ { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+ { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+ { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
+ { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
+ { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
+ { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
+ { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 },
+ { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
+ { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+ { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
+ { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+ { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+ { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
+ { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
+ { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+ { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+ { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+ { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
+ { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
+ { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
+ { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
+ { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
+ { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
+ { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
+ { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
+ { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
+ { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
+ { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
+ { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+};
+
+static const u32 ar5416Common_9160[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020015 },
+ { 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 },
+ { 0x00007010, 0x00000020 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x40000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x00000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x000080c0, 0x2a82301a },
+ { 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, 0x08f04800 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0x00000000 },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x32143320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c4, 0x00000000 },
+ { 0x000081d0, 0x00003210 },
+ { 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 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x00000000 },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x00008300, 0x00000000 },
+ { 0x00008304, 0x00000000 },
+ { 0x00008308, 0x00000000 },
+ { 0x0000830c, 0x00000000 },
+ { 0x00008310, 0x00000000 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008318, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000007 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00000000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x000107ff },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xad848e19 },
+ { 0x00009810, 0x7d14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x00009840, 0x206a01ae },
+ { 0x0000984c, 0x1284233c },
+ { 0x00009854, 0x00000859 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x05100000 },
+ { 0x0000a920, 0x05100000 },
+ { 0x0000b920, 0x05100000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009948, 0x9280b212 },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0x5f3ca3de },
+ { 0x00009958, 0x2108ecff },
+ { 0x00009940, 0x00750604 },
+ { 0x0000c95c, 0x004b6a8e },
+ { 0x0000c968, 0x000003ce },
+ { 0x00009970, 0x190fb515 },
+ { 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, 0x006f0000 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000200 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099fc, 0x00001042 },
+ { 0x00009b00, 0x00000000 },
+ { 0x00009b04, 0x00000001 },
+ { 0x00009b08, 0x00000002 },
+ { 0x00009b0c, 0x00000003 },
+ { 0x00009b10, 0x00000004 },
+ { 0x00009b14, 0x00000005 },
+ { 0x00009b18, 0x00000008 },
+ { 0x00009b1c, 0x00000009 },
+ { 0x00009b20, 0x0000000a },
+ { 0x00009b24, 0x0000000b },
+ { 0x00009b28, 0x0000000c },
+ { 0x00009b2c, 0x0000000d },
+ { 0x00009b30, 0x00000010 },
+ { 0x00009b34, 0x00000011 },
+ { 0x00009b38, 0x00000012 },
+ { 0x00009b3c, 0x00000013 },
+ { 0x00009b40, 0x00000014 },
+ { 0x00009b44, 0x00000015 },
+ { 0x00009b48, 0x00000018 },
+ { 0x00009b4c, 0x00000019 },
+ { 0x00009b50, 0x0000001a },
+ { 0x00009b54, 0x0000001b },
+ { 0x00009b58, 0x0000001c },
+ { 0x00009b5c, 0x0000001d },
+ { 0x00009b60, 0x00000020 },
+ { 0x00009b64, 0x00000021 },
+ { 0x00009b68, 0x00000022 },
+ { 0x00009b6c, 0x00000023 },
+ { 0x00009b70, 0x00000024 },
+ { 0x00009b74, 0x00000025 },
+ { 0x00009b78, 0x00000028 },
+ { 0x00009b7c, 0x00000029 },
+ { 0x00009b80, 0x0000002a },
+ { 0x00009b84, 0x0000002b },
+ { 0x00009b88, 0x0000002c },
+ { 0x00009b8c, 0x0000002d },
+ { 0x00009b90, 0x00000030 },
+ { 0x00009b94, 0x00000031 },
+ { 0x00009b98, 0x00000032 },
+ { 0x00009b9c, 0x00000033 },
+ { 0x00009ba0, 0x00000034 },
+ { 0x00009ba4, 0x00000035 },
+ { 0x00009ba8, 0x00000035 },
+ { 0x00009bac, 0x00000035 },
+ { 0x00009bb0, 0x00000035 },
+ { 0x00009bb4, 0x00000035 },
+ { 0x00009bb8, 0x00000035 },
+ { 0x00009bbc, 0x00000035 },
+ { 0x00009bc0, 0x00000035 },
+ { 0x00009bc4, 0x00000035 },
+ { 0x00009bc8, 0x00000035 },
+ { 0x00009bcc, 0x00000035 },
+ { 0x00009bd0, 0x00000035 },
+ { 0x00009bd4, 0x00000035 },
+ { 0x00009bd8, 0x00000035 },
+ { 0x00009bdc, 0x00000035 },
+ { 0x00009be0, 0x00000035 },
+ { 0x00009be4, 0x00000035 },
+ { 0x00009be8, 0x00000035 },
+ { 0x00009bec, 0x00000035 },
+ { 0x00009bf0, 0x00000035 },
+ { 0x00009bf4, 0x00000035 },
+ { 0x00009bf8, 0x00000010 },
+ { 0x00009bfc, 0x0000001a },
+ { 0x0000a210, 0x40806333 },
+ { 0x0000a214, 0x00106c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x018830c6 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x001a0bb5 },
+ { 0x0000a22c, 0x00000000 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a23c, 0x13c889af },
+ { 0x0000a240, 0x38490a20 },
+ { 0x0000a244, 0x00007bb6 },
+ { 0x0000a248, 0x0fff3ffc },
+ { 0x0000a24c, 0x00000001 },
+ { 0x0000a250, 0x0000a000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0cc75380 },
+ { 0x0000a25c, 0x0f0f0f01 },
+ { 0x0000a260, 0xdfa91f01 },
+ { 0x0000a268, 0x00000001 },
+ { 0x0000a26c, 0x0ebae9c6 },
+ { 0x0000b26c, 0x0ebae9c6 },
+ { 0x0000c26c, 0x0ebae9c6 },
+ { 0x0000d270, 0x00820820 },
+ { 0x0000a278, 0x1ce739ce },
+ { 0x0000a27c, 0x050701ce },
+ { 0x0000a338, 0x00000000 },
+ { 0x0000a33c, 0x00000000 },
+ { 0x0000a340, 0x00000000 },
+ { 0x0000a344, 0x00000000 },
+ { 0x0000a348, 0x3fffffff },
+ { 0x0000a34c, 0x3fffffff },
+ { 0x0000a350, 0x3fffffff },
+ { 0x0000a354, 0x0003ffff },
+ { 0x0000a358, 0x79a8aa33 },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x1ce739ce },
+ { 0x0000a398, 0x000001ce },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3a0, 0x00000000 },
+ { 0x0000a3a4, 0x00000000 },
+ { 0x0000a3a8, 0x00000000 },
+ { 0x0000a3ac, 0x00000000 },
+ { 0x0000a3b0, 0x00000000 },
+ { 0x0000a3b4, 0x00000000 },
+ { 0x0000a3b8, 0x00000000 },
+ { 0x0000a3bc, 0x00000000 },
+ { 0x0000a3c0, 0x00000000 },
+ { 0x0000a3c4, 0x00000000 },
+ { 0x0000a3c8, 0x00000246 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x1ce739ce },
+ { 0x0000a3e0, 0x000001ce },
+};
+
+static const u32 ar5416Bank0_9160[][2] = {
+ { 0x000098b0, 0x1e5795e5 },
+ { 0x000098e0, 0x02008020 },
+};
+
+static const u32 ar5416BB_RfGain_9160[][3] = {
+ { 0x00009a00, 0x00000000, 0x00000000 },
+ { 0x00009a04, 0x00000040, 0x00000040 },
+ { 0x00009a08, 0x00000080, 0x00000080 },
+ { 0x00009a0c, 0x000001a1, 0x00000141 },
+ { 0x00009a10, 0x000001e1, 0x00000181 },
+ { 0x00009a14, 0x00000021, 0x000001c1 },
+ { 0x00009a18, 0x00000061, 0x00000001 },
+ { 0x00009a1c, 0x00000168, 0x00000041 },
+ { 0x00009a20, 0x000001a8, 0x000001a8 },
+ { 0x00009a24, 0x000001e8, 0x000001e8 },
+ { 0x00009a28, 0x00000028, 0x00000028 },
+ { 0x00009a2c, 0x00000068, 0x00000068 },
+ { 0x00009a30, 0x00000189, 0x000000a8 },
+ { 0x00009a34, 0x000001c9, 0x00000169 },
+ { 0x00009a38, 0x00000009, 0x000001a9 },
+ { 0x00009a3c, 0x00000049, 0x000001e9 },
+ { 0x00009a40, 0x00000089, 0x00000029 },
+ { 0x00009a44, 0x00000170, 0x00000069 },
+ { 0x00009a48, 0x000001b0, 0x00000190 },
+ { 0x00009a4c, 0x000001f0, 0x000001d0 },
+ { 0x00009a50, 0x00000030, 0x00000010 },
+ { 0x00009a54, 0x00000070, 0x00000050 },
+ { 0x00009a58, 0x00000191, 0x00000090 },
+ { 0x00009a5c, 0x000001d1, 0x00000151 },
+ { 0x00009a60, 0x00000011, 0x00000191 },
+ { 0x00009a64, 0x00000051, 0x000001d1 },
+ { 0x00009a68, 0x00000091, 0x00000011 },
+ { 0x00009a6c, 0x000001b8, 0x00000051 },
+ { 0x00009a70, 0x000001f8, 0x00000198 },
+ { 0x00009a74, 0x00000038, 0x000001d8 },
+ { 0x00009a78, 0x00000078, 0x00000018 },
+ { 0x00009a7c, 0x00000199, 0x00000058 },
+ { 0x00009a80, 0x000001d9, 0x00000098 },
+ { 0x00009a84, 0x00000019, 0x00000159 },
+ { 0x00009a88, 0x00000059, 0x00000199 },
+ { 0x00009a8c, 0x00000099, 0x000001d9 },
+ { 0x00009a90, 0x000000d9, 0x00000019 },
+ { 0x00009a94, 0x000000f9, 0x00000059 },
+ { 0x00009a98, 0x000000f9, 0x00000099 },
+ { 0x00009a9c, 0x000000f9, 0x000000d9 },
+ { 0x00009aa0, 0x000000f9, 0x000000f9 },
+ { 0x00009aa4, 0x000000f9, 0x000000f9 },
+ { 0x00009aa8, 0x000000f9, 0x000000f9 },
+ { 0x00009aac, 0x000000f9, 0x000000f9 },
+ { 0x00009ab0, 0x000000f9, 0x000000f9 },
+ { 0x00009ab4, 0x000000f9, 0x000000f9 },
+ { 0x00009ab8, 0x000000f9, 0x000000f9 },
+ { 0x00009abc, 0x000000f9, 0x000000f9 },
+ { 0x00009ac0, 0x000000f9, 0x000000f9 },
+ { 0x00009ac4, 0x000000f9, 0x000000f9 },
+ { 0x00009ac8, 0x000000f9, 0x000000f9 },
+ { 0x00009acc, 0x000000f9, 0x000000f9 },
+ { 0x00009ad0, 0x000000f9, 0x000000f9 },
+ { 0x00009ad4, 0x000000f9, 0x000000f9 },
+ { 0x00009ad8, 0x000000f9, 0x000000f9 },
+ { 0x00009adc, 0x000000f9, 0x000000f9 },
+ { 0x00009ae0, 0x000000f9, 0x000000f9 },
+ { 0x00009ae4, 0x000000f9, 0x000000f9 },
+ { 0x00009ae8, 0x000000f9, 0x000000f9 },
+ { 0x00009aec, 0x000000f9, 0x000000f9 },
+ { 0x00009af0, 0x000000f9, 0x000000f9 },
+ { 0x00009af4, 0x000000f9, 0x000000f9 },
+ { 0x00009af8, 0x000000f9, 0x000000f9 },
+ { 0x00009afc, 0x000000f9, 0x000000f9 },
+};
+
+static const u32 ar5416Bank1_9160[][2] = {
+ { 0x000098b0, 0x02108421 },
+ { 0x000098ec, 0x00000008 },
+};
+
+static const u32 ar5416Bank2_9160[][2] = {
+ { 0x000098b0, 0x0e73ff17 },
+ { 0x000098e0, 0x00000420 },
+};
+
+static const u32 ar5416Bank3_9160[][3] = {
+ { 0x000098f0, 0x01400018, 0x01c00018 },
+};
+
+static const u32 ar5416Bank6_9160[][3] = {
+
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00e00000, 0x00e00000 },
+ { 0x0000989c, 0x005e0000, 0x005e0000 },
+ { 0x0000989c, 0x00120000, 0x00120000 },
+ { 0x0000989c, 0x00620000, 0x00620000 },
+ { 0x0000989c, 0x00020000, 0x00020000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x40ff0000, 0x40ff0000 },
+ { 0x0000989c, 0x005f0000, 0x005f0000 },
+ { 0x0000989c, 0x00870000, 0x00870000 },
+ { 0x0000989c, 0x00f90000, 0x00f90000 },
+ { 0x0000989c, 0x007b0000, 0x007b0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00f50000, 0x00f50000 },
+ { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+ { 0x0000989c, 0x00110000, 0x00110000 },
+ { 0x0000989c, 0x006100a8, 0x006100a8 },
+ { 0x0000989c, 0x004210a2, 0x004210a2 },
+ { 0x0000989c, 0x0014008f, 0x0014008f },
+ { 0x0000989c, 0x00c40003, 0x00c40003 },
+ { 0x0000989c, 0x003000f2, 0x003000f2 },
+ { 0x0000989c, 0x00440016, 0x00440016 },
+ { 0x0000989c, 0x00410040, 0x00410040 },
+ { 0x0000989c, 0x0001805e, 0x0001805e },
+ { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
+ { 0x0000989c, 0x000000f1, 0x000000f1 },
+ { 0x0000989c, 0x00002081, 0x00002081 },
+ { 0x0000989c, 0x000000d4, 0x000000d4 },
+ { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+static const u32 ar5416Bank6TPC_9160[][3] = {
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00000000, 0x00000000 },
+ { 0x0000989c, 0x00e00000, 0x00e00000 },
+ { 0x0000989c, 0x005e0000, 0x005e0000 },
+ { 0x0000989c, 0x00120000, 0x00120000 },
+ { 0x0000989c, 0x00620000, 0x00620000 },
+ { 0x0000989c, 0x00020000, 0x00020000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x40ff0000, 0x40ff0000 },
+ { 0x0000989c, 0x005f0000, 0x005f0000 },
+ { 0x0000989c, 0x00870000, 0x00870000 },
+ { 0x0000989c, 0x00f90000, 0x00f90000 },
+ { 0x0000989c, 0x007b0000, 0x007b0000 },
+ { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+ { 0x0000989c, 0x00f50000, 0x00f50000 },
+ { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+ { 0x0000989c, 0x00110000, 0x00110000 },
+ { 0x0000989c, 0x006100a8, 0x006100a8 },
+ { 0x0000989c, 0x00423022, 0x00423022 },
+ { 0x0000989c, 0x2014008f, 0x2014008f },
+ { 0x0000989c, 0x00c40002, 0x00c40002 },
+ { 0x0000989c, 0x003000f2, 0x003000f2 },
+ { 0x0000989c, 0x00440016, 0x00440016 },
+ { 0x0000989c, 0x00410040, 0x00410040 },
+ { 0x0000989c, 0x0001805e, 0x0001805e },
+ { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
+ { 0x0000989c, 0x000000e1, 0x000000e1 },
+ { 0x0000989c, 0x00007080, 0x00007080 },
+ { 0x0000989c, 0x000000d4, 0x000000d4 },
+ { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+static const u32 ar5416Bank7_9160[][2] = {
+ { 0x0000989c, 0x00000500 },
+ { 0x0000989c, 0x00000800 },
+ { 0x000098cc, 0x0000000e },
+};
+
+
+static u32 ar5416Addac_9160[][2] = {
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x000000c0 },
+ {0x0000989c, 0x00000018 },
+ {0x0000989c, 0x00000004 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x000000c0 },
+ {0x0000989c, 0x00000019 },
+ {0x0000989c, 0x00000004 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000004 },
+ {0x0000989c, 0x00000003 },
+ {0x0000989c, 0x00000008 },
+ {0x0000989c, 0x00000000 },
+ {0x000098cc, 0x00000000 },
+};
+
+
+static u32 ar5416Addac_91601_1[][2] = {
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x000000c0 },
+ {0x0000989c, 0x00000018 },
+ {0x0000989c, 0x00000004 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x000000c0 },
+ {0x0000989c, 0x00000019 },
+ {0x0000989c, 0x00000004 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x0000989c, 0x00000000 },
+ {0x000098cc, 0x00000000 },
+};
+
+
+
+static const u32 ar9280Modes_9280[][6] = {
+ { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+ { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+ { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+ { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
+ { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801080, 0x08400840, 0x06e006e0 },
+ { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f },
+ { 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 },
+ { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 },
+ { 0x00009848, 0x00028566, 0x00028566, 0x00028563, 0x00028563, 0x00028563 },
+ { 0x0000a848, 0x00028566, 0x00028566, 0x00028563, 0x00028563, 0x00028563 },
+ { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
+ { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
+ { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+ { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d20, 0x00049d20, 0x00049d18 },
+ { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x5ac64190, 0x5ac64190, 0x5ac64190, 0x5ac64190, 0x5ac64190 },
+ { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
+ { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+ { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 },
+ { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
+ { 0x0000c9b8, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a },
+ { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+ { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+ { 0x000099c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c },
+ { 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, 0x00008184, 0x00008184, 0x00000214, 0x00000214, 0x00000214 },
+ { 0x00009a04, 0x00008188, 0x00008188, 0x00000218, 0x00000218, 0x00000218 },
+ { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000224, 0x00000224, 0x00000224 },
+ { 0x00009a0c, 0x00008190, 0x00008190, 0x00000228, 0x00000228, 0x00000228 },
+ { 0x00009a10, 0x00008194, 0x00008194, 0x0000022c, 0x0000022c, 0x0000022c },
+ { 0x00009a14, 0x00008200, 0x00008200, 0x00000230, 0x00000230, 0x00000230 },
+ { 0x00009a18, 0x00008204, 0x00008204, 0x000002a4, 0x000002a4, 0x000002a4 },
+ { 0x00009a1c, 0x00008208, 0x00008208, 0x000002a8, 0x000002a8, 0x000002a8 },
+ { 0x00009a20, 0x0000820c, 0x0000820c, 0x000002ac, 0x000002ac, 0x000002ac },
+ { 0x00009a24, 0x00008210, 0x00008210, 0x000002b0, 0x000002b0, 0x000002b0 },
+ { 0x00009a28, 0x00008214, 0x00008214, 0x000002b4, 0x000002b4, 0x000002b4 },
+ { 0x00009a2c, 0x00008280, 0x00008280, 0x000002b8, 0x000002b8, 0x000002b8 },
+ { 0x00009a30, 0x00008284, 0x00008284, 0x00000390, 0x00000390, 0x00000390 },
+ { 0x00009a34, 0x00008288, 0x00008288, 0x00000394, 0x00000394, 0x00000394 },
+ { 0x00009a38, 0x0000828c, 0x0000828c, 0x00000398, 0x00000398, 0x00000398 },
+ { 0x00009a3c, 0x00008290, 0x00008290, 0x00000334, 0x00000334, 0x00000334 },
+ { 0x00009a40, 0x00008300, 0x00008300, 0x00000338, 0x00000338, 0x00000338 },
+ { 0x00009a44, 0x00008304, 0x00008304, 0x000003ac, 0x000003ac, 0x000003ac },
+ { 0x00009a48, 0x00008308, 0x00008308, 0x000003b0, 0x000003b0, 0x000003b0 },
+ { 0x00009a4c, 0x0000830c, 0x0000830c, 0x000003b4, 0x000003b4, 0x000003b4 },
+ { 0x00009a50, 0x00008310, 0x00008310, 0x000003b8, 0x000003b8, 0x000003b8 },
+ { 0x00009a54, 0x00008314, 0x00008314, 0x000003a5, 0x000003a5, 0x000003a5 },
+ { 0x00009a58, 0x00008380, 0x00008380, 0x000003a9, 0x000003a9, 0x000003a9 },
+ { 0x00009a5c, 0x00008384, 0x00008384, 0x000003ad, 0x000003ad, 0x000003ad },
+ { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+ { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+ { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+ { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+ { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+ { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+ { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+ { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+ { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+ { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+ { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+ { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+ { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+ { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+ { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+ { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+ { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+ { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+ { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+ { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+ { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+ { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+ { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+ { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+ { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
+ { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
+ { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
+ { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
+ { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
+ { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
+ { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
+ { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
+ { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
+ { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
+ { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c },
+ { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 },
+ { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 },
+ { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 },
+ { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 },
+ { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 },
+ { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 },
+ { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 },
+ { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 },
+ { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 },
+ { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 },
+ { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 },
+ { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 },
+ { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c },
+ { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 },
+ { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 },
+ { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 },
+ { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 },
+ { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 },
+ { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 },
+ { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 },
+ { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 },
+ { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad },
+ { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 },
+ { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 },
+ { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 },
+ { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 },
+ { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 },
+ { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 },
+ { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 },
+ { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 },
+ { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 },
+ { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca },
+ { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce },
+ { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 },
+ { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 },
+ { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 },
+ { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 },
+ { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb },
+ { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf },
+ { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 },
+ { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 },
+ { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 },
+ { 0x0000a20c, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019 },
+ { 0x0000b20c, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019, 0x000c6019 },
+ { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
+ { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
+ { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b },
+ { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 },
+ { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 },
+ { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a },
+ { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 },
+ { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
+ { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b },
+ { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 },
+ { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 },
+ { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a },
+ { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 },
+ { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b },
+ { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 },
+ { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 },
+ { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a },
+ { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 },
+ { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a },
+ { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 },
+ { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 },
+ { 0x0000784c, 0x0e4f048c, 0x0e4f048c, 0x0e4d048c, 0x0e4d048c, 0x0e4d048c },
+ { 0x00007854, 0x12031828, 0x12031828, 0x12035828, 0x12035828, 0x12035828 },
+ { 0x00007870, 0x807ec400, 0x807ec400, 0x807ec000, 0x807ec000, 0x807ec000 },
+ { 0x0000788c, 0x00010000, 0x00010000, 0x00110000, 0x00110000, 0x00110000 },
+};
+
+static const u32 ar9280Common_9280[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020015 },
+ { 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 },
+ { 0x00007010, 0x00000033 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x40000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x00000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x00008070, 0x00000000 },
+ { 0x000080c0, 0x2a82301a },
+ { 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, 0x08f04800 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0x00000000 },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x32143320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c4, 0x00000000 },
+ { 0x000081d0, 0x00003210 },
+ { 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 },
+ { 0x00008270, 0x00000000 },
+ { 0x00008274, 0x40000000 },
+ { 0x00008278, 0x003e4180 },
+ { 0x0000827c, 0x00000000 },
+ { 0x00008284, 0x0000002c },
+ { 0x00008288, 0x0000002c },
+ { 0x0000828c, 0x00000000 },
+ { 0x00008294, 0x00000000 },
+ { 0x00008298, 0x00000000 },
+ { 0x00008300, 0x00000000 },
+ { 0x00008304, 0x00000000 },
+ { 0x00008308, 0x00000000 },
+ { 0x0000830c, 0x00000000 },
+ { 0x00008310, 0x00000000 },
+ { 0x00008314, 0x00000000 },
+ { 0x00008318, 0x00000000 },
+ { 0x00008328, 0x00000000 },
+ { 0x0000832c, 0x00000007 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00000000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x000107ff },
+ { 0x00008344, 0x00000000 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xaf268e30 },
+ { 0x00009810, 0xfd14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x00009840, 0x206a01ae },
+ { 0x0000984c, 0x0040233c },
+ { 0x0000a84c, 0x0040233c },
+ { 0x00009854, 0x00000044 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x04900000 },
+ { 0x0000a920, 0x04900000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009948, 0x9280c00a },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0xe250a51e },
+ { 0x00009958, 0x3388ffff },
+ { 0x00009940, 0x00781204 },
+ { 0x0000c95c, 0x004b6a8e },
+ { 0x0000c968, 0x000003ce },
+ { 0x00009970, 0x190fb514 },
+ { 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, 0x006f00c4 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099b4, 0x00000820 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000000 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099fc, 0x00001042 },
+ { 0x0000a210, 0x4080a333 },
+ { 0x0000a214, 0x40206c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x01834061 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x000003b5 },
+ { 0x0000a22c, 0x23277200 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a23c, 0x13c889af },
+ { 0x0000a240, 0x38490a20 },
+ { 0x0000a244, 0x00007bb6 },
+ { 0x0000a248, 0x0fff3ffc },
+ { 0x0000a24c, 0x00000001 },
+ { 0x0000a250, 0x001da000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0cdbd380 },
+ { 0x0000a25c, 0x0f0f0f01 },
+ { 0x0000a260, 0xdfa91f01 },
+ { 0x0000a268, 0x00000000 },
+ { 0x0000a26c, 0x0ebae9c6 },
+ { 0x0000b26c, 0x0ebae9c6 },
+ { 0x0000d270, 0x00820820 },
+ { 0x0000a278, 0x1ce739ce },
+ { 0x0000a27c, 0x050701ce },
+ { 0x0000a358, 0x7999aa0f },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x1ce739ce },
+ { 0x0000a398, 0x000001ce },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3a0, 0x00000000 },
+ { 0x0000a3a4, 0x00000000 },
+ { 0x0000a3a8, 0x00000000 },
+ { 0x0000a3ac, 0x00000000 },
+ { 0x0000a3b0, 0x00000000 },
+ { 0x0000a3b4, 0x00000000 },
+ { 0x0000a3b8, 0x00000000 },
+ { 0x0000a3bc, 0x00000000 },
+ { 0x0000a3c0, 0x00000000 },
+ { 0x0000a3c4, 0x00000000 },
+ { 0x0000a3c8, 0x00000246 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x1ce739ce },
+ { 0x0000a3e0, 0x000001ce },
+ { 0x0000a3e4, 0x00000000 },
+ { 0x0000a3e8, 0x18c43433 },
+ { 0x0000a3ec, 0x00f38081 },
+ { 0x00007800, 0x00040000 },
+ { 0x00007804, 0xdb005012 },
+ { 0x00007808, 0x04924914 },
+ { 0x0000780c, 0x21084210 },
+ { 0x00007810, 0x6d801300 },
+ { 0x00007814, 0x0019beff },
+ { 0x00007818, 0x07e40000 },
+ { 0x0000781c, 0x00492000 },
+ { 0x00007820, 0x92492480 },
+ { 0x00007824, 0x00040000 },
+ { 0x00007828, 0xdb005012 },
+ { 0x0000782c, 0x04924914 },
+ { 0x00007830, 0x21084210 },
+ { 0x00007834, 0x6d801300 },
+ { 0x00007838, 0x0019beff },
+ { 0x0000783c, 0x07e40000 },
+ { 0x00007840, 0x00492000 },
+ { 0x00007844, 0x92492480 },
+ { 0x00007848, 0x00120000 },
+ { 0x00007850, 0x54214514 },
+ { 0x00007858, 0x92592692 },
+ { 0x00007860, 0x52802000 },
+ { 0x00007864, 0x0a8e370e },
+ { 0x00007868, 0xc0102850 },
+ { 0x0000786c, 0x812d4000 },
+ { 0x00007874, 0x001b6db0 },
+ { 0x00007878, 0x00376b63 },
+ { 0x0000787c, 0x06db6db6 },
+ { 0x00007880, 0x006d8000 },
+ { 0x00007884, 0xffeffffe },
+ { 0x00007888, 0xffeffffe },
+ { 0x00007890, 0x00060aeb },
+ { 0x00007894, 0x5a108000 },
+ { 0x00007898, 0x2a850160 },
+};
+
+
+
+
+static const u32 ar9280Modes_9280_2[][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, 0x206a022e, 0x206a022e, 0x206a022e },
+ { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
+ { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 },
+ { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
+ { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e },
+ { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+ { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
+ { 0x0000c864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+ { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+ { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 },
+ { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+ { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+ { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+ { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 },
+ { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 },
+ { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 },
+ { 0x0000c9b8, 0x0000000f, 0x0000000f, 0x0000001c, 0x0000001c, 0x0000001c },
+ { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
+ { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+ { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+ { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
+ { 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, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 },
+ { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 },
+ { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 },
+ { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 },
+ { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c },
+ { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 },
+ { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 },
+ { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 },
+ { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c },
+ { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 },
+ { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 },
+ { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 },
+ { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c },
+ { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 },
+ { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 },
+ { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 },
+ { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c },
+ { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 },
+ { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 },
+ { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 },
+ { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 },
+ { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 },
+ { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c },
+ { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 },
+ { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 },
+ { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 },
+ { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c },
+ { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 },
+ { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 },
+ { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 },
+ { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 },
+ { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 },
+ { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 },
+ { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 },
+ { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 },
+ { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c },
+ { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 },
+ { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 },
+ { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 },
+ { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 },
+ { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 },
+ { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c },
+ { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 },
+ { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 },
+ { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 },
+ { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 },
+ { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 },
+ { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c },
+ { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 },
+ { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 },
+ { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 },
+ { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c },
+ { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 },
+ { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 },
+ { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 },
+ { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 },
+ { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c },
+ { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 },
+ { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c },
+ { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 },
+ { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 },
+ { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 },
+ { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 },
+ { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 },
+ { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 },
+ { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 },
+ { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 },
+ { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 },
+ { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 },
+ { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 },
+ { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 },
+ { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c },
+ { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 },
+ { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 },
+ { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 },
+ { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 },
+ { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 },
+ { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 },
+ { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 },
+ { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 },
+ { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad },
+ { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 },
+ { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 },
+ { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 },
+ { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 },
+ { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 },
+ { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 },
+ { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 },
+ { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 },
+ { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 },
+ { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca },
+ { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce },
+ { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 },
+ { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 },
+ { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 },
+ { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 },
+ { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb },
+ { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf },
+ { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 },
+ { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db },
+ { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 },
+ { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 },
+ { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
+ { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 },
+ { 0x0000a21c, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a },
+ { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+ { 0x0000a250, 0x001ff000, 0x001ff000, 0x001da000, 0x001da000, 0x001da000 },
+ { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 },
+ { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 },
+ { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 },
+ { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b },
+ { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 },
+ { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 },
+ { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a },
+ { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 },
+ { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 },
+ { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b },
+ { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 },
+ { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 },
+ { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a },
+ { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 },
+ { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b },
+ { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 },
+ { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 },
+ { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a },
+ { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 },
+ { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a },
+ { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 },
+ { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 },
+ { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
+ { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 },
+};
+
+static const u32 ar9280Common_9280_2[][2] = {
+ { 0x0000000c, 0x00000000 },
+ { 0x00000030, 0x00020015 },
+ { 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 },
+ { 0x00007010, 0x00000033 },
+ { 0x00007034, 0x00000002 },
+ { 0x00007038, 0x000004c2 },
+ { 0x00008004, 0x00000000 },
+ { 0x00008008, 0x00000000 },
+ { 0x0000800c, 0x00000000 },
+ { 0x00008018, 0x00000700 },
+ { 0x00008020, 0x00000000 },
+ { 0x00008038, 0x00000000 },
+ { 0x0000803c, 0x00000000 },
+ { 0x00008048, 0x40000000 },
+ { 0x00008054, 0x00000000 },
+ { 0x00008058, 0x00000000 },
+ { 0x0000805c, 0x000fc78f },
+ { 0x00008060, 0x0000000f },
+ { 0x00008064, 0x00000000 },
+ { 0x00008070, 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, 0x08f04800 },
+ { 0x00008124, 0x00000000 },
+ { 0x00008128, 0x00000000 },
+ { 0x0000812c, 0x00000000 },
+ { 0x00008130, 0x00000000 },
+ { 0x00008134, 0x00000000 },
+ { 0x00008138, 0x00000000 },
+ { 0x0000813c, 0x00000000 },
+ { 0x00008144, 0x00000000 },
+ { 0x00008168, 0x00000000 },
+ { 0x0000816c, 0x00000000 },
+ { 0x00008170, 0x32143320 },
+ { 0x00008174, 0xfaa4fa50 },
+ { 0x00008178, 0x00000100 },
+ { 0x0000817c, 0x00000000 },
+ { 0x000081c0, 0x00000000 },
+ { 0x000081d0, 0x00003210 },
+ { 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 },
+ { 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, 0x00000007 },
+ { 0x00008330, 0x00000302 },
+ { 0x00008334, 0x00000e00 },
+ { 0x00008338, 0x00000000 },
+ { 0x0000833c, 0x00000000 },
+ { 0x00008340, 0x000107ff },
+ { 0x00008344, 0x00581043 },
+ { 0x00009808, 0x00000000 },
+ { 0x0000980c, 0xafa68e30 },
+ { 0x00009810, 0xfd14e000 },
+ { 0x00009814, 0x9c0a9f6b },
+ { 0x0000981c, 0x00000000 },
+ { 0x0000982c, 0x0000a000 },
+ { 0x00009830, 0x00000000 },
+ { 0x0000983c, 0x00200400 },
+ { 0x0000984c, 0x0040233c },
+ { 0x0000a84c, 0x0040233c },
+ { 0x00009854, 0x00000044 },
+ { 0x00009900, 0x00000000 },
+ { 0x00009904, 0x00000000 },
+ { 0x00009908, 0x00000000 },
+ { 0x0000990c, 0x00000000 },
+ { 0x00009910, 0x01002310 },
+ { 0x0000991c, 0x10000fff },
+ { 0x00009920, 0x04900000 },
+ { 0x0000a920, 0x04900000 },
+ { 0x00009928, 0x00000001 },
+ { 0x0000992c, 0x00000004 },
+ { 0x00009934, 0x1e1f2022 },
+ { 0x00009938, 0x0a0b0c0d },
+ { 0x0000993c, 0x00000000 },
+ { 0x00009948, 0x9280c00a },
+ { 0x0000994c, 0x00020028 },
+ { 0x00009954, 0x5f3ca3de },
+ { 0x00009958, 0x2108ecff },
+ { 0x00009940, 0x14750604 },
+ { 0x0000c95c, 0x004b6a8e },
+ { 0x0000c968, 0x000003ce },
+ { 0x00009970, 0x190fb515 },
+ { 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, 0x006f0000 },
+ { 0x000099b0, 0x03051000 },
+ { 0x000099b4, 0x00000820 },
+ { 0x000099dc, 0x00000000 },
+ { 0x000099e0, 0x00000000 },
+ { 0x000099e4, 0xaaaaaaaa },
+ { 0x000099e8, 0x3c466478 },
+ { 0x000099ec, 0x0cc80caa },
+ { 0x000099f0, 0x00000000 },
+ { 0x000099fc, 0x00001042 },
+ { 0x0000a210, 0x4080a333 },
+ { 0x0000a214, 0x40206c10 },
+ { 0x0000a218, 0x009c4060 },
+ { 0x0000a220, 0x01834061 },
+ { 0x0000a224, 0x00000400 },
+ { 0x0000a228, 0x000003b5 },
+ { 0x0000a22c, 0x233f71c0 },
+ { 0x0000a234, 0x20202020 },
+ { 0x0000a238, 0x20202020 },
+ { 0x0000a23c, 0x13c88000 },
+ { 0x0000a240, 0x38490a20 },
+ { 0x0000a244, 0x00007bb6 },
+ { 0x0000a248, 0x0fff3ffc },
+ { 0x0000a24c, 0x00000000 },
+ { 0x0000a254, 0x00000000 },
+ { 0x0000a258, 0x0cdbd380 },
+ { 0x0000a25c, 0x0f0f0f01 },
+ { 0x0000a260, 0xdfa91f01 },
+ { 0x0000a268, 0x00000000 },
+ { 0x0000a26c, 0x0ebae9c6 },
+ { 0x0000b26c, 0x0ebae9c6 },
+ { 0x0000d270, 0x00820820 },
+ { 0x0000a278, 0x1ce739ce },
+ { 0x0000a27c, 0x050701ce },
+ { 0x0000d35c, 0x07ffffef },
+ { 0x0000d360, 0x0fffffe7 },
+ { 0x0000d364, 0x17ffffe5 },
+ { 0x0000d368, 0x1fffffe4 },
+ { 0x0000d36c, 0x37ffffe3 },
+ { 0x0000d370, 0x3fffffe3 },
+ { 0x0000d374, 0x57ffffe3 },
+ { 0x0000d378, 0x5fffffe2 },
+ { 0x0000d37c, 0x7fffffe2 },
+ { 0x0000d380, 0x7f3c7bba },
+ { 0x0000d384, 0xf3307ff0 },
+ { 0x0000a388, 0x0c000000 },
+ { 0x0000a38c, 0x20202020 },
+ { 0x0000a390, 0x20202020 },
+ { 0x0000a394, 0x1ce739ce },
+ { 0x0000a398, 0x000001ce },
+ { 0x0000a39c, 0x00000001 },
+ { 0x0000a3a0, 0x00000000 },
+ { 0x0000a3a4, 0x00000000 },
+ { 0x0000a3a8, 0x00000000 },
+ { 0x0000a3ac, 0x00000000 },
+ { 0x0000a3b0, 0x00000000 },
+ { 0x0000a3b4, 0x00000000 },
+ { 0x0000a3b8, 0x00000000 },
+ { 0x0000a3bc, 0x00000000 },
+ { 0x0000a3c0, 0x00000000 },
+ { 0x0000a3c4, 0x00000000 },
+ { 0x0000a3c8, 0x00000246 },
+ { 0x0000a3cc, 0x20202020 },
+ { 0x0000a3d0, 0x20202020 },
+ { 0x0000a3d4, 0x20202020 },
+ { 0x0000a3dc, 0x1ce739ce },
+ { 0x0000a3e0, 0x000001ce },
+ { 0x0000a3e4, 0x00000000 },
+ { 0x0000a3e8, 0x18c43433 },
+ { 0x0000a3ec, 0x00f70081 },
+ { 0x00007800, 0x00040000 },
+ { 0x00007804, 0xdb005012 },
+ { 0x00007808, 0x04924914 },
+ { 0x0000780c, 0x21084210 },
+ { 0x00007810, 0x6d801300 },
+ { 0x00007814, 0x0019beff },
+ { 0x00007818, 0x07e41000 },
+ { 0x0000781c, 0x00392000 },
+ { 0x00007820, 0x92592480 },
+ { 0x00007824, 0x00040000 },
+ { 0x00007828, 0xdb005012 },
+ { 0x0000782c, 0x04924914 },
+ { 0x00007830, 0x21084210 },
+ { 0x00007834, 0x6d801300 },
+ { 0x00007838, 0x0019beff },
+ { 0x0000783c, 0x07e40000 },
+ { 0x00007840, 0x00392000 },
+ { 0x00007844, 0x92592480 },
+ { 0x00007848, 0x00100000 },
+ { 0x0000784c, 0x773f0567 },
+ { 0x00007850, 0x54214514 },
+ { 0x00007854, 0x12035828 },
+ { 0x00007858, 0x9259269a },
+ { 0x00007860, 0x52802000 },
+ { 0x00007864, 0x0a8e370e },
+ { 0x00007868, 0xc0102850 },
+ { 0x0000786c, 0x812d4000 },
+ { 0x00007870, 0x807ec400 },
+ { 0x00007874, 0x001b6db0 },
+ { 0x00007878, 0x00376b63 },
+ { 0x0000787c, 0x06db6db6 },
+ { 0x00007880, 0x006d8000 },
+ { 0x00007884, 0xffeffffe },
+ { 0x00007888, 0xffeffffe },
+ { 0x0000788c, 0x00010000 },
+ { 0x00007890, 0x02060aeb },
+ { 0x00007898, 0x2a850160 },
+};
+
+static const u32 ar9280Modes_fast_clock_9280_2[][3] = {
+ { 0x00001030, 0x00000268, 0x000004d0 },
+ { 0x00001070, 0x0000018c, 0x00000318 },
+ { 0x000010b0, 0x00000fd0, 0x00001fa0 },
+ { 0x00008014, 0x044c044c, 0x08980898 },
+ { 0x0000801c, 0x148ec02b, 0x148ec057 },
+ { 0x00008318, 0x000044c0, 0x00008980 },
+ { 0x00009820, 0x02020200, 0x02020200 },
+ { 0x00009824, 0x00000f0f, 0x00000f0f },
+ { 0x00009828, 0x0b020001, 0x0b020001 },
+ { 0x00009834, 0x00000f0f, 0x00000f0f },
+ { 0x00009844, 0x03721821, 0x03721821 },
+ { 0x00009914, 0x00000898, 0x00000898 },
+ { 0x00009918, 0x0000000b, 0x00000016 },
+ { 0x00009944, 0xdfbc1210, 0xdfbc1210 },
+};
+
+
+
+static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0x401dcffc },
+ {0x00004040, 0x1aaabe40 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
+
+
+
+static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
+ {0x00004040, 0x9248fd00 },
+ {0x00004040, 0x24924924 },
+ {0x00004040, 0xa8000019 },
+ {0x00004040, 0x13160820 },
+ {0x00004040, 0xe5980560 },
+ {0x00004040, 0x401dcffd },
+ {0x00004040, 0x1aaabe40 },
+ {0x00004040, 0xbe105554 },
+ {0x00004040, 0x00043007 },
+ {0x00004044, 0x00000000 },
+};
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
new file mode 100644
index 00000000000..99badf1404c
--- /dev/null
+++ b/drivers/net/wireless/ath9k/main.c
@@ -0,0 +1,1494 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* mac80211 and PCI callbacks */
+
+#include <linux/nl80211.h>
+#include "core.h"
+
+#define ATH_PCI_VERSION "0.1"
+
+#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13
+#define IEEE80211_ACTION_CAT_HT 7
+#define IEEE80211_ACTION_HT_TXCHWIDTH 0
+
+static char *dev_info = "ath9k";
+
+MODULE_AUTHOR("Atheros Communications");
+MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
+MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct pci_device_id ath_pci_id_table[] __devinitdata = {
+ { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */
+ { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */
+ { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */
+ { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
+ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
+ { 0 }
+};
+
+static int ath_get_channel(struct ath_softc *sc,
+ struct ieee80211_channel *chan)
+{
+ int i;
+
+ for (i = 0; i < sc->sc_ah->ah_nchan; i++) {
+ if (sc->sc_ah->ah_channels[i].channel == chan->center_freq)
+ return i;
+ }
+
+ return -1;
+}
+
+static u32 ath_get_extchanmode(struct ath_softc *sc,
+ struct ieee80211_channel *chan)
+{
+ u32 chanmode = 0;
+ u8 ext_chan_offset = sc->sc_ht_info.ext_chan_offset;
+ enum ath9k_ht_macmode tx_chan_width = sc->sc_ht_info.tx_chan_width;
+
+ switch (chan->band) {
+ case IEEE80211_BAND_2GHZ:
+ if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_20))
+ chanmode = CHANNEL_G_HT20;
+ if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ chanmode = CHANNEL_G_HT40PLUS;
+ if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ chanmode = CHANNEL_G_HT40MINUS;
+ break;
+ case IEEE80211_BAND_5GHZ:
+ if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_20))
+ chanmode = CHANNEL_A_HT20;
+ if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ chanmode = CHANNEL_A_HT40PLUS;
+ if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ chanmode = CHANNEL_A_HT40MINUS;
+ break;
+ default:
+ break;
+ }
+
+ return chanmode;
+}
+
+
+static int ath_setkey_tkip(struct ath_softc *sc,
+ struct ieee80211_key_conf *key,
+ struct ath9k_keyval *hk,
+ const u8 *addr)
+{
+ u8 *key_rxmic = NULL;
+ u8 *key_txmic = NULL;
+
+ key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
+ key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
+
+ if (addr == NULL) {
+ /* Group key installation */
+ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+ return ath_keyset(sc, key->keyidx, hk, addr);
+ }
+ if (!sc->sc_splitmic) {
+ /*
+ * data key goes at first index,
+ * the hal handles the MIC keys at index+64.
+ */
+ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+ memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
+ return ath_keyset(sc, key->keyidx, hk, addr);
+ }
+ /*
+ * TX key goes at first index, RX key at +32.
+ * The hal handles the MIC keys at index+64.
+ */
+ memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
+ if (!ath_keyset(sc, key->keyidx, hk, NULL)) {
+ /* Txmic entry failed. No need to proceed further */
+ DPRINTF(sc, ATH_DBG_KEYCACHE,
+ "%s Setting TX MIC Key Failed\n", __func__);
+ return 0;
+ }
+
+ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+ /* XXX delete tx key on failure? */
+ return ath_keyset(sc, key->keyidx+32, hk, addr);
+}
+
+static int ath_key_config(struct ath_softc *sc,
+ const u8 *addr,
+ struct ieee80211_key_conf *key)
+{
+ struct ieee80211_vif *vif;
+ struct ath9k_keyval hk;
+ const u8 *mac = NULL;
+ int ret = 0;
+ enum ieee80211_if_types opmode;
+
+ memset(&hk, 0, sizeof(hk));
+
+ switch (key->alg) {
+ case ALG_WEP:
+ hk.kv_type = ATH9K_CIPHER_WEP;
+ break;
+ case ALG_TKIP:
+ hk.kv_type = ATH9K_CIPHER_TKIP;
+ break;
+ case ALG_CCMP:
+ hk.kv_type = ATH9K_CIPHER_AES_CCM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ hk.kv_len = key->keylen;
+ memcpy(hk.kv_val, key->key, key->keylen);
+
+ if (!sc->sc_vaps[0])
+ return -EIO;
+
+ vif = sc->sc_vaps[0]->av_if_data;
+ opmode = vif->type;
+
+ /*
+ * Strategy:
+ * For _M_STA mc tx, we will not setup a key at all since we never
+ * tx mc.
+ * _M_STA mc rx, we will use the keyID.
+ * for _M_IBSS mc tx, we will use the keyID, and no macaddr.
+ * for _M_IBSS mc rx, we will alloc a slot and plumb the mac of the
+ * peer node. BUT we will plumb a cleartext key so that we can do
+ * perSta default key table lookup in software.
+ */
+ if (is_broadcast_ether_addr(addr)) {
+ switch (opmode) {
+ case IEEE80211_IF_TYPE_STA:
+ /* default key: could be group WPA key
+ * or could be static WEP key */
+ mac = NULL;
+ break;
+ case IEEE80211_IF_TYPE_IBSS:
+ break;
+ case IEEE80211_IF_TYPE_AP:
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ } else {
+ mac = addr;
+ }
+
+ if (key->alg == ALG_TKIP)
+ ret = ath_setkey_tkip(sc, key, &hk, mac);
+ else
+ ret = ath_keyset(sc, key->keyidx, &hk, mac);
+
+ if (!ret)
+ return -EIO;
+
+ if (mac)
+ sc->sc_keytype = hk.kv_type;
+ return 0;
+}
+
+static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key)
+{
+#define ATH_MAX_NUM_KEYS 4
+ int freeslot;
+
+ freeslot = (key->keyidx >= ATH_MAX_NUM_KEYS) ? 1 : 0;
+ ath_key_reset(sc, key->keyidx, freeslot);
+#undef ATH_MAX_NUM_KEYS
+}
+
+static void setup_ht_cap(struct ieee80211_ht_info *ht_info)
+{
+/* Until mac80211 includes these fields */
+
+#define IEEE80211_HT_CAP_DSSSCCK40 0x1000
+#define IEEE80211_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */
+#define IEEE80211_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */
+
+ ht_info->ht_supported = 1;
+ ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH
+ |(u16)IEEE80211_HT_CAP_MIMO_PS
+ |(u16)IEEE80211_HT_CAP_SGI_40
+ |(u16)IEEE80211_HT_CAP_DSSSCCK40;
+
+ ht_info->ampdu_factor = IEEE80211_HT_CAP_MAXRXAMPDU_65536;
+ ht_info->ampdu_density = IEEE80211_HT_CAP_MPDUDENSITY_8;
+ /* setup supported mcs set */
+ memset(ht_info->supp_mcs_set, 0, 16);
+ ht_info->supp_mcs_set[0] = 0xff;
+ ht_info->supp_mcs_set[1] = 0xff;
+ ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED;
+}
+
+static int ath_rate2idx(struct ath_softc *sc, int rate)
+{
+ int i = 0, cur_band, n_rates;
+ struct ieee80211_hw *hw = sc->hw;
+
+ cur_band = hw->conf.channel->band;
+ n_rates = sc->sbands[cur_band].n_bitrates;
+
+ for (i = 0; i < n_rates; i++) {
+ if (sc->sbands[cur_band].bitrates[i].bitrate == rate)
+ break;
+ }
+
+ /*
+ * NB:mac80211 validates rx rate index against the supported legacy rate
+ * index only (should be done against ht rates also), return the highest
+ * legacy rate index for rx rate which does not match any one of the
+ * supported basic and extended rates to make mac80211 happy.
+ * The following hack will be cleaned up once the issue with
+ * the rx rate index validation in mac80211 is fixed.
+ */
+ if (i == n_rates)
+ return n_rates - 1;
+ return i;
+}
+
+static void ath9k_rx_prepare(struct ath_softc *sc,
+ struct sk_buff *skb,
+ struct ath_recv_status *status,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_channel *curchan = hw->conf.channel;
+
+ memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+
+ rx_status->mactime = status->tsf;
+ rx_status->band = curchan->band;
+ rx_status->freq = curchan->center_freq;
+ rx_status->noise = ATH_DEFAULT_NOISE_FLOOR;
+ rx_status->signal = rx_status->noise + status->rssi;
+ rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100));
+ rx_status->antenna = status->antenna;
+ rx_status->qual = status->rssi * 100 / 64;
+
+ if (status->flags & ATH_RX_MIC_ERROR)
+ rx_status->flag |= RX_FLAG_MMIC_ERROR;
+ if (status->flags & ATH_RX_FCS_ERROR)
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+ rx_status->flag |= RX_FLAG_TSFT;
+}
+
+static u8 parse_mpdudensity(u8 mpdudensity)
+{
+ /*
+ * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
+ * 0 for no restriction
+ * 1 for 1/4 us
+ * 2 for 1/2 us
+ * 3 for 1 us
+ * 4 for 2 us
+ * 5 for 4 us
+ * 6 for 8 us
+ * 7 for 16 us
+ */
+ switch (mpdudensity) {
+ case 0:
+ return 0;
+ case 1:
+ case 2:
+ case 3:
+ /* Our lower layer calculations limit our precision to
+ 1 microsecond */
+ return 1;
+ case 4:
+ return 2;
+ case 5:
+ return 4;
+ case 6:
+ return 8;
+ case 7:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+static int ath9k_start(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ieee80211_channel *curchan = hw->conf.channel;
+ int error = 0, pos;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with "
+ "initial channel: %d MHz\n", __func__, curchan->center_freq);
+
+ /* setup initial channel */
+
+ pos = ath_get_channel(sc, curchan);
+ if (pos == -1) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
+ return -EINVAL;
+ }
+
+ sc->sc_ah->ah_channels[pos].chanmode =
+ (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A;
+
+ /* open ath_dev */
+ error = ath_open(sc, &sc->sc_ah->ah_channels[pos]);
+ if (error) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to complete ath_open\n", __func__);
+ return error;
+ }
+
+ ieee80211_wake_queues(hw);
+ return 0;
+}
+
+static int ath9k_tx(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ struct ath_softc *sc = hw->priv;
+ int hdrlen, padsize;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ /*
+ * As a temporary workaround, assign seq# here; this will likely need
+ * to be cleaned up to work better with Beacon transmission and virtual
+ * BSSes.
+ */
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+ sc->seq_no += 0x10;
+ hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(sc->seq_no);
+ }
+
+ /* Add the padding after the header if this is not already done */
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ if (hdrlen & 3) {
+ padsize = hdrlen % 4;
+ if (skb_headroom(skb) < padsize)
+ return -1;
+ skb_push(skb, padsize);
+ memmove(skb->data, skb->data + padsize, hdrlen);
+ }
+
+ DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n",
+ __func__,
+ skb);
+
+ if (ath_tx_start(sc, skb) != 0) {
+ DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__);
+ dev_kfree_skb_any(skb);
+ /* FIXME: Check for proper return value from ATH_DEV */
+ return 0;
+ }
+
+ return 0;
+}
+
+static void ath9k_stop(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+ int error;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__);
+
+ error = ath_suspend(sc);
+ if (error)
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: Device is no longer present\n", __func__);
+
+ ieee80211_stop_queues(hw);
+}
+
+static int ath9k_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct ath_softc *sc = hw->priv;
+ int error, ic_opmode = 0;
+
+ /* Support only vap for now */
+
+ if (sc->sc_nvaps)
+ return -ENOBUFS;
+
+ switch (conf->type) {
+ case IEEE80211_IF_TYPE_STA:
+ ic_opmode = ATH9K_M_STA;
+ break;
+ case IEEE80211_IF_TYPE_IBSS:
+ ic_opmode = ATH9K_M_IBSS;
+ break;
+ default:
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Only STA and IBSS are supported currently\n",
+ __func__);
+ return -EOPNOTSUPP;
+ }
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n",
+ __func__,
+ ic_opmode);
+
+ error = ath_vap_attach(sc, 0, conf->vif, ic_opmode);
+ if (error) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to attach vap, error: %d\n",
+ __func__, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static void ath9k_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_vap *avp;
+ int error;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__);
+
+ avp = sc->sc_vaps[0];
+ if (avp == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
+ __func__);
+ return;
+ }
+
+#ifdef CONFIG_SLOW_ANT_DIV
+ ath_slow_ant_div_stop(&sc->sc_antdiv);
+#endif
+
+ /* Update ratectrl */
+ ath_rate_newstate(sc, avp);
+
+ /* Reclaim beacon resources */
+ if (sc->sc_opmode == ATH9K_M_HOSTAP || sc->sc_opmode == ATH9K_M_IBSS) {
+ ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
+ ath_beacon_return(sc, avp);
+ }
+
+ /* Set interrupt mask */
+ sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+ ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL);
+ sc->sc_beacons = 0;
+
+ error = ath_vap_detach(sc, 0);
+ if (error)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to detach vap, error: %d\n",
+ __func__, error);
+}
+
+static int ath9k_config(struct ieee80211_hw *hw,
+ struct ieee80211_conf *conf)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ieee80211_channel *curchan = hw->conf.channel;
+ int pos;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
+ __func__,
+ curchan->center_freq);
+
+ pos = ath_get_channel(sc, curchan);
+ if (pos == -1) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
+ return -EINVAL;
+ }
+
+ sc->sc_ah->ah_channels[pos].chanmode =
+ (curchan->band == IEEE80211_BAND_2GHZ) ?
+ CHANNEL_G : CHANNEL_A;
+
+ if (sc->sc_curaid && hw->conf.ht_conf.ht_supported)
+ sc->sc_ah->ah_channels[pos].chanmode =
+ ath_get_extchanmode(sc, curchan);
+
+ sc->sc_config.txpowlimit = 2 * conf->power_level;
+
+ /* set h/w channel */
+ if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n",
+ __func__);
+
+ return 0;
+}
+
+static int ath9k_config_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_if_conf *conf)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_vap *avp;
+ u32 rfilt = 0;
+ int error, i;
+ DECLARE_MAC_BUF(mac);
+
+ avp = sc->sc_vaps[0];
+ if (avp == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if ((conf->changed & IEEE80211_IFCC_BSSID) &&
+ !is_zero_ether_addr(conf->bssid)) {
+ switch (vif->type) {
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ /* Update ratectrl about the new state */
+ ath_rate_newstate(sc, avp);
+
+ /* Set rx filter */
+ rfilt = ath_calcrxfilter(sc);
+ ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
+
+ /* Set BSSID */
+ memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN);
+ sc->sc_curaid = 0;
+ ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
+ sc->sc_curaid);
+
+ /* Set aggregation protection mode parameters */
+ sc->sc_config.ath_aggr_prot = 0;
+
+ /*
+ * Reset our TSF so that its value is lower than the
+ * beacon that we are trying to catch.
+ * Only then hw will update its TSF register with the
+ * new beacon. Reset the TSF before setting the BSSID
+ * to avoid allowing in any frames that would update
+ * our TSF only to have us clear it
+ * immediately thereafter.
+ */
+ ath9k_hw_reset_tsf(sc->sc_ah);
+
+ /* Disable BMISS interrupt when we're not associated */
+ ath9k_hw_set_interrupts(sc->sc_ah,
+ sc->sc_imask &
+ ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS));
+ sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: RX filter 0x%x bssid %s aid 0x%x\n",
+ __func__, rfilt,
+ print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
+
+ /* need to reconfigure the beacon */
+ sc->sc_beacons = 0;
+
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((conf->changed & IEEE80211_IFCC_BEACON) &&
+ (vif->type == IEEE80211_IF_TYPE_IBSS)) {
+ /*
+ * Allocate and setup the beacon frame.
+ *
+ * Stop any previous beacon DMA. This may be
+ * necessary, for example, when an ibss merge
+ * causes reconfiguration; we may be called
+ * with beacon transmission active.
+ */
+ ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
+
+ error = ath_beacon_alloc(sc, 0);
+ if (error != 0)
+ return error;
+
+ ath_beacon_sync(sc, 0);
+ }
+
+ /* Check for WLAN_CAPABILITY_PRIVACY ? */
+ if ((avp->av_opmode != IEEE80211_IF_TYPE_STA)) {
+ for (i = 0; i < IEEE80211_WEP_NKID; i++)
+ if (ath9k_hw_keyisvalid(sc->sc_ah, (u16)i))
+ ath9k_hw_keysetmac(sc->sc_ah,
+ (u16)i,
+ sc->sc_curbssid);
+ }
+
+ /* Only legacy IBSS for now */
+ if (vif->type == IEEE80211_IF_TYPE_IBSS)
+ ath_update_chainmask(sc, 0);
+
+ return 0;
+}
+
+#define SUPPORTED_FILTERS \
+ (FIF_PROMISC_IN_BSS | \
+ FIF_ALLMULTI | \
+ FIF_CONTROL | \
+ FIF_OTHER_BSS | \
+ FIF_BCN_PRBRESP_PROMISC | \
+ FIF_FCSFAIL)
+
+/* Accept unicast, bcast and mcast frames */
+
+static void ath9k_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_mc_list *mclist)
+{
+ struct ath_softc *sc = hw->priv;
+
+ changed_flags &= SUPPORTED_FILTERS;
+ *total_flags &= SUPPORTED_FILTERS;
+
+ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ ath_scan_start(sc);
+ else
+ ath_scan_end(sc);
+ }
+}
+
+static void ath9k_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ const u8 *addr)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_node *an;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ spin_lock_irqsave(&sc->node_lock, flags);
+ an = ath_node_find(sc, (u8 *) addr);
+ spin_unlock_irqrestore(&sc->node_lock, flags);
+
+ switch (cmd) {
+ case STA_NOTIFY_ADD:
+ spin_lock_irqsave(&sc->node_lock, flags);
+ if (!an) {
+ ath_node_attach(sc, (u8 *)addr, 0);
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n",
+ __func__,
+ print_mac(mac, addr));
+ } else {
+ ath_node_get(sc, (u8 *)addr);
+ }
+ spin_unlock_irqrestore(&sc->node_lock, flags);
+ break;
+ case STA_NOTIFY_REMOVE:
+ if (!an)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Removal of a non-existent node\n",
+ __func__);
+ else {
+ ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT);
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n",
+ __func__,
+ print_mac(mac, addr));
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int ath9k_conf_tx(struct ieee80211_hw *hw,
+ u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath9k_tx_queue_info qi;
+ int ret = 0, qnum;
+
+ if (queue >= WME_NUM_AC)
+ return 0;
+
+ qi.tqi_aifs = params->aifs;
+ qi.tqi_cwmin = params->cw_min;
+ qi.tqi_cwmax = params->cw_max;
+ qi.tqi_burstTime = params->txop;
+ qnum = ath_get_hal_qnum(queue, sc);
+
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: Configure tx [queue/halq] [%d/%d], "
+ "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
+ __func__,
+ queue,
+ qnum,
+ params->aifs,
+ params->cw_min,
+ params->cw_max,
+ params->txop);
+
+ ret = ath_txq_update(sc, qnum, &qi);
+ if (ret)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: TXQ Update failed\n", __func__);
+
+ return ret;
+}
+
+static int ath9k_set_key(struct ieee80211_hw *hw,
+ enum set_key_cmd cmd,
+ const u8 *local_addr,
+ const u8 *addr,
+ struct ieee80211_key_conf *key)
+{
+ struct ath_softc *sc = hw->priv;
+ int ret = 0;
+
+ DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__);
+
+ switch (cmd) {
+ case SET_KEY:
+ ret = ath_key_config(sc, addr, key);
+ if (!ret) {
+ set_bit(key->keyidx, sc->sc_keymap);
+ key->hw_key_idx = key->keyidx;
+ /* push IV and Michael MIC generation to stack */
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ if (key->alg == ALG_TKIP)
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ }
+ break;
+ case DISABLE_KEY:
+ ath_key_delete(sc, key);
+ clear_bit(key->keyidx, sc->sc_keymap);
+ sc->sc_keytype = ATH9K_CIPHER_CLR;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void ath9k_ht_conf(struct ath_softc *sc,
+ struct ieee80211_bss_conf *bss_conf)
+{
+#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14)
+ struct ath_ht_info *ht_info = &sc->sc_ht_info;
+
+ if (bss_conf->assoc_ht) {
+ ht_info->ext_chan_offset =
+ bss_conf->ht_bss_conf->bss_cap &
+ IEEE80211_HT_IE_CHA_SEC_OFFSET;
+
+ if (!(bss_conf->ht_conf->cap &
+ IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
+ (bss_conf->ht_bss_conf->bss_cap &
+ IEEE80211_HT_IE_CHA_WIDTH))
+ ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040;
+ else
+ ht_info->tx_chan_width = ATH9K_HT_MACMODE_20;
+
+ ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width);
+ ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
+ bss_conf->ht_conf->ampdu_factor);
+ ht_info->mpdudensity =
+ parse_mpdudensity(bss_conf->ht_conf->ampdu_density);
+
+ }
+
+#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT
+}
+
+static void ath9k_bss_assoc_info(struct ath_softc *sc,
+ struct ieee80211_bss_conf *bss_conf)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_channel *curchan = hw->conf.channel;
+ struct ath_vap *avp;
+ int pos;
+ DECLARE_MAC_BUF(mac);
+
+ if (bss_conf->assoc) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n",
+ __func__,
+ bss_conf->aid);
+
+ avp = sc->sc_vaps[0];
+ if (avp == NULL) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
+ __func__);
+ return;
+ }
+
+ /* New association, store aid */
+ if (avp->av_opmode == ATH9K_M_STA) {
+ sc->sc_curaid = bss_conf->aid;
+ ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
+ sc->sc_curaid);
+ }
+
+ /* Configure the beacon */
+ ath_beacon_config(sc, 0);
+ sc->sc_beacons = 1;
+
+ /* Reset rssi stats */
+ sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
+ sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
+ sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
+ sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
+
+ /* Update chainmask */
+ ath_update_chainmask(sc, bss_conf->assoc_ht);
+
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: bssid %s aid 0x%x\n",
+ __func__,
+ print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
+ __func__,
+ curchan->center_freq);
+
+ pos = ath_get_channel(sc, curchan);
+ if (pos == -1) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Invalid channel\n", __func__);
+ return;
+ }
+
+ if (hw->conf.ht_conf.ht_supported)
+ sc->sc_ah->ah_channels[pos].chanmode =
+ ath_get_extchanmode(sc, curchan);
+ else
+ sc->sc_ah->ah_channels[pos].chanmode =
+ (curchan->band == IEEE80211_BAND_2GHZ) ?
+ CHANNEL_G : CHANNEL_A;
+
+ /* set h/w channel */
+ if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to set channel\n",
+ __func__);
+
+ ath_rate_newstate(sc, avp);
+ /* Update ratectrl about the new state */
+ ath_rc_node_update(hw, avp->rc_node);
+ } else {
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: Bss Info DISSOC\n", __func__);
+ sc->sc_curaid = 0;
+ }
+}
+
+static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf,
+ u32 changed)
+{
+ struct ath_softc *sc = hw->priv;
+
+ if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n",
+ __func__,
+ bss_conf->use_short_preamble);
+ if (bss_conf->use_short_preamble)
+ sc->sc_flags |= ATH_PREAMBLE_SHORT;
+ else
+ sc->sc_flags &= ~ATH_PREAMBLE_SHORT;
+ }
+
+ if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n",
+ __func__,
+ bss_conf->use_cts_prot);
+ if (bss_conf->use_cts_prot &&
+ hw->conf.channel->band != IEEE80211_BAND_5GHZ)
+ sc->sc_flags |= ATH_PROTECT_ENABLE;
+ else
+ sc->sc_flags &= ~ATH_PROTECT_ENABLE;
+ }
+
+ if (changed & BSS_CHANGED_HT) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n",
+ __func__,
+ bss_conf->assoc_ht);
+ ath9k_ht_conf(sc, bss_conf);
+ }
+
+ if (changed & BSS_CHANGED_ASSOC) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n",
+ __func__,
+ bss_conf->assoc);
+ ath9k_bss_assoc_info(sc, bss_conf);
+ }
+}
+
+static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
+{
+ u64 tsf;
+ struct ath_softc *sc = hw->priv;
+ struct ath_hal *ah = sc->sc_ah;
+
+ tsf = ath9k_hw_gettsf64(ah);
+
+ return tsf;
+}
+
+static void ath9k_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hal *ah = sc->sc_ah;
+
+ ath9k_hw_reset_tsf(ah);
+}
+
+static int ath9k_ampdu_action(struct ieee80211_hw *hw,
+ enum ieee80211_ampdu_mlme_action action,
+ const u8 *addr,
+ u16 tid,
+ u16 *ssn)
+{
+ struct ath_softc *sc = hw->priv;
+ int ret = 0;
+
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ ret = ath_rx_aggr_start(sc, addr, tid, ssn);
+ if (ret < 0)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to start RX aggregation\n",
+ __func__);
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+ ret = ath_rx_aggr_stop(sc, addr, tid);
+ if (ret < 0)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to stop RX aggregation\n",
+ __func__);
+ break;
+ case IEEE80211_AMPDU_TX_START:
+ ret = ath_tx_aggr_start(sc, addr, tid, ssn);
+ if (ret < 0)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to start TX aggregation\n",
+ __func__);
+ else
+ ieee80211_start_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_STOP:
+ ret = ath_tx_aggr_stop(sc, addr, tid);
+ if (ret < 0)
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to stop TX aggregation\n",
+ __func__);
+
+ ieee80211_stop_tx_ba_cb_irqsafe(hw, (u8 *)addr, tid);
+ break;
+ default:
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unknown AMPDU action\n", __func__);
+ }
+
+ return ret;
+}
+
+static struct ieee80211_ops ath9k_ops = {
+ .tx = ath9k_tx,
+ .start = ath9k_start,
+ .stop = ath9k_stop,
+ .add_interface = ath9k_add_interface,
+ .remove_interface = ath9k_remove_interface,
+ .config = ath9k_config,
+ .config_interface = ath9k_config_interface,
+ .configure_filter = ath9k_configure_filter,
+ .get_stats = NULL,
+ .sta_notify = ath9k_sta_notify,
+ .conf_tx = ath9k_conf_tx,
+ .get_tx_stats = NULL,
+ .bss_info_changed = ath9k_bss_info_changed,
+ .set_tim = NULL,
+ .set_key = ath9k_set_key,
+ .hw_scan = NULL,
+ .get_tkip_seq = NULL,
+ .set_rts_threshold = NULL,
+ .set_frag_threshold = NULL,
+ .set_retry_limit = NULL,
+ .get_tsf = ath9k_get_tsf,
+ .reset_tsf = ath9k_reset_tsf,
+ .tx_last_beacon = NULL,
+ .ampdu_action = ath9k_ampdu_action
+};
+
+void ath_get_beaconconfig(struct ath_softc *sc,
+ int if_id,
+ struct ath_beacon_config *conf)
+{
+ struct ieee80211_hw *hw = sc->hw;
+
+ /* fill in beacon config data */
+
+ conf->beacon_interval = hw->conf.beacon_int;
+ conf->listen_interval = 100;
+ conf->dtim_count = 1;
+ conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
+}
+
+int ath_update_beacon(struct ath_softc *sc,
+ int if_id,
+ struct ath_beacon_offset *bo,
+ struct sk_buff *skb,
+ int mcast)
+{
+ return 0;
+}
+
+void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
+ struct ath_xmit_status *tx_status, struct ath_node *an)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+
+ DPRINTF(sc, ATH_DBG_XMIT,
+ "%s: TX complete: skb: %p\n", __func__, skb);
+
+ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
+ tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
+ /* free driver's private data area of tx_info */
+ if (tx_info->driver_data[0] != NULL)
+ kfree(tx_info->driver_data[0]);
+ tx_info->driver_data[0] = NULL;
+ }
+
+ if (tx_status->flags & ATH_TX_BAR) {
+ tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+ tx_status->flags &= ~ATH_TX_BAR;
+ }
+
+ if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
+ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+ /* Frame was not ACKed, but an ACK was expected */
+ tx_info->status.excessive_retries = 1;
+ }
+ } else {
+ /* Frame was ACKed */
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ }
+
+ tx_info->status.retry_count = tx_status->retries;
+
+ ieee80211_tx_status(hw, skb);
+ if (an)
+ ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE);
+}
+
+int ath__rx_indicate(struct ath_softc *sc,
+ struct sk_buff *skb,
+ struct ath_recv_status *status,
+ u16 keyix)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_node *an = NULL;
+ struct ieee80211_rx_status rx_status;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ int padsize;
+ enum ATH_RX_TYPE st;
+
+ /* see if any padding is done by the hw and remove it */
+ if (hdrlen & 3) {
+ padsize = hdrlen % 4;
+ memmove(skb->data + padsize, skb->data, hdrlen);
+ skb_pull(skb, padsize);
+ }
+
+ /* remove FCS before passing up to protocol stack */
+ skb_trim(skb, (skb->len - FCS_LEN));
+
+ /* Prepare rx status */
+ ath9k_rx_prepare(sc, skb, status, &rx_status);
+
+ if (!(keyix == ATH9K_RXKEYIX_INVALID) &&
+ !(status->flags & ATH_RX_DECRYPT_ERROR)) {
+ rx_status.flag |= RX_FLAG_DECRYPTED;
+ } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
+ && !(status->flags & ATH_RX_DECRYPT_ERROR)
+ && skb->len >= hdrlen + 4) {
+ keyix = skb->data[hdrlen + 3] >> 6;
+
+ if (test_bit(keyix, sc->sc_keymap))
+ rx_status.flag |= RX_FLAG_DECRYPTED;
+ }
+
+ spin_lock_bh(&sc->node_lock);
+ an = ath_node_find(sc, hdr->addr2);
+ spin_unlock_bh(&sc->node_lock);
+
+ if (an) {
+ ath_rx_input(sc, an,
+ hw->conf.ht_conf.ht_supported,
+ skb, status, &st);
+ }
+ if (!an || (st != ATH_RX_CONSUMED))
+ __ieee80211_rx(hw, skb, &rx_status);
+
+ return 0;
+}
+
+int ath_rx_subframe(struct ath_node *an,
+ struct sk_buff *skb,
+ struct ath_recv_status *status)
+{
+ struct ath_softc *sc = an->an_sc;
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_rx_status rx_status;
+
+ /* Prepare rx status */
+ ath9k_rx_prepare(sc, skb, status, &rx_status);
+ if (!(status->flags & ATH_RX_DECRYPT_ERROR))
+ rx_status.flag |= RX_FLAG_DECRYPTED;
+
+ __ieee80211_rx(hw, skb, &rx_status);
+
+ return 0;
+}
+
+enum ath9k_ht_macmode ath_cwm_macmode(struct ath_softc *sc)
+{
+ return sc->sc_ht_info.tx_chan_width;
+}
+
+static int ath_detach(struct ath_softc *sc)
+{
+ struct ieee80211_hw *hw = sc->hw;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
+
+ /* Unregister hw */
+
+ ieee80211_unregister_hw(hw);
+
+ /* unregister Rate control */
+ ath_rate_control_unregister();
+
+ /* tx/rx cleanup */
+
+ ath_rx_cleanup(sc);
+ ath_tx_cleanup(sc);
+
+ /* Deinit */
+
+ ath_deinit(sc);
+
+ return 0;
+}
+
+static int ath_attach(u16 devid,
+ struct ath_softc *sc)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ int error = 0;
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__);
+
+ error = ath_init(devid, sc);
+ if (error != 0)
+ return error;
+
+ /* Init nodes */
+
+ INIT_LIST_HEAD(&sc->node_list);
+ spin_lock_init(&sc->node_lock);
+
+ /* get mac address from hardware and set in mac80211 */
+
+ SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
+
+ /* setup channels and rates */
+
+ sc->sbands[IEEE80211_BAND_2GHZ].channels =
+ sc->channels[IEEE80211_BAND_2GHZ];
+ sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
+ sc->rates[IEEE80211_BAND_2GHZ];
+ sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
+
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
+ /* Setup HT capabilities for 2.4Ghz*/
+ setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info);
+
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ &sc->sbands[IEEE80211_BAND_2GHZ];
+
+ if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
+ sc->sbands[IEEE80211_BAND_5GHZ].channels =
+ sc->channels[IEEE80211_BAND_5GHZ];
+ sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
+ sc->rates[IEEE80211_BAND_5GHZ];
+ sc->sbands[IEEE80211_BAND_5GHZ].band =
+ IEEE80211_BAND_5GHZ;
+
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
+ /* Setup HT capabilities for 5Ghz*/
+ setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info);
+
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &sc->sbands[IEEE80211_BAND_5GHZ];
+ }
+
+ /* FIXME: Have to figure out proper hw init values later */
+
+ hw->queues = 4;
+ hw->ampdu_queues = 1;
+
+ /* Register rate control */
+ hw->rate_control_algorithm = "ath9k_rate_control";
+ error = ath_rate_control_register();
+ if (error != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to register rate control "
+ "algorithm:%d\n", __func__, error);
+ ath_rate_control_unregister();
+ goto bad;
+ }
+
+ error = ieee80211_register_hw(hw);
+ if (error != 0) {
+ ath_rate_control_unregister();
+ goto bad;
+ }
+
+ /* initialize tx/rx engine */
+
+ error = ath_tx_init(sc, ATH_TXBUF);
+ if (error != 0)
+ goto bad1;
+
+ error = ath_rx_init(sc, ATH_RXBUF);
+ if (error != 0)
+ goto bad1;
+
+ return 0;
+bad1:
+ ath_detach(sc);
+bad:
+ return error;
+}
+
+static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ void __iomem *mem;
+ struct ath_softc *sc;
+ struct ieee80211_hw *hw;
+ const char *athname;
+ u8 csz;
+ u32 val;
+ int ret = 0;
+
+ if (pci_enable_device(pdev))
+ return -EIO;
+
+ /* XXX 32-bit addressing only */
+ if (pci_set_dma_mask(pdev, 0xffffffff)) {
+ printk(KERN_ERR "ath_pci: 32-bit DMA not available\n");
+ ret = -ENODEV;
+ goto bad;
+ }
+
+ /*
+ * Cache line size is used to size and align various
+ * structures used to communicate with the hardware.
+ */
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
+ if (csz == 0) {
+ /*
+ * Linux 2.4.18 (at least) writes the cache line size
+ * register as a 16-bit wide register which is wrong.
+ * We must have this setup properly for rx buffer
+ * DMA to work so force a reasonable value here if it
+ * comes up zero.
+ */
+ csz = L1_CACHE_BYTES / sizeof(u32);
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
+ }
+ /*
+ * The default setting of latency timer yields poor results,
+ * set it to the value used by other systems. It may be worth
+ * tweaking this setting more.
+ */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
+
+ pci_set_master(pdev);
+
+ /*
+ * Disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state.
+ */
+ pci_read_config_dword(pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+ ret = pci_request_region(pdev, 0, "ath9k");
+ if (ret) {
+ dev_err(&pdev->dev, "PCI memory region reserve error\n");
+ ret = -ENODEV;
+ goto bad;
+ }
+
+ mem = pci_iomap(pdev, 0, 0);
+ if (!mem) {
+ printk(KERN_ERR "PCI memory map error\n") ;
+ ret = -EIO;
+ goto bad1;
+ }
+
+ hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
+ if (hw == NULL) {
+ printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n");
+ goto bad2;
+ }
+
+ hw->flags = IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM;
+
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+ pci_set_drvdata(pdev, hw);
+
+ sc = hw->priv;
+ sc->hw = hw;
+ sc->pdev = pdev;
+ sc->mem = mem;
+
+ if (ath_attach(id->device, sc) != 0) {
+ ret = -ENODEV;
+ goto bad3;
+ }
+
+ /* setup interrupt service routine */
+
+ if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) {
+ printk(KERN_ERR "%s: request_irq failed\n",
+ wiphy_name(hw->wiphy));
+ ret = -EIO;
+ goto bad4;
+ }
+
+ athname = ath9k_hw_probe(id->vendor, id->device);
+
+ printk(KERN_INFO "%s: %s: mem=0x%lx, irq=%d\n",
+ wiphy_name(hw->wiphy),
+ athname ? athname : "Atheros ???",
+ (unsigned long)mem, pdev->irq);
+
+ return 0;
+bad4:
+ ath_detach(sc);
+bad3:
+ ieee80211_free_hw(hw);
+bad2:
+ pci_iounmap(pdev, mem);
+bad1:
+ pci_release_region(pdev, 0);
+bad:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void ath_pci_remove(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct ath_softc *sc = hw->priv;
+
+ if (pdev->irq)
+ free_irq(pdev->irq, sc);
+ ath_detach(sc);
+ pci_iounmap(pdev, sc->mem);
+ pci_release_region(pdev, 0);
+ pci_disable_device(pdev);
+ ieee80211_free_hw(hw);
+}
+
+#ifdef CONFIG_PM
+
+static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, 3);
+
+ return 0;
+}
+
+static int ath_pci_resume(struct pci_dev *pdev)
+{
+ u32 val;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+ pci_restore_state(pdev);
+ /*
+ * Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state
+ */
+ pci_read_config_dword(pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+MODULE_DEVICE_TABLE(pci, ath_pci_id_table);
+
+static struct pci_driver ath_pci_driver = {
+ .name = "ath9k",
+ .id_table = ath_pci_id_table,
+ .probe = ath_pci_probe,
+ .remove = ath_pci_remove,
+#ifdef CONFIG_PM
+ .suspend = ath_pci_suspend,
+ .resume = ath_pci_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init init_ath_pci(void)
+{
+ printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION);
+
+ if (pci_register_driver(&ath_pci_driver) < 0) {
+ printk(KERN_ERR
+ "ath_pci: No devices found, driver not installed.\n");
+ pci_unregister_driver(&ath_pci_driver);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+module_init(init_ath_pci);
+
+static void __exit exit_ath_pci(void)
+{
+ pci_unregister_driver(&ath_pci_driver);
+ printk(KERN_INFO "%s: driver unloaded\n", dev_info);
+}
+module_exit(exit_ath_pci);
diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c
new file mode 100644
index 00000000000..eb9121fdfd3
--- /dev/null
+++ b/drivers/net/wireless/ath9k/phy.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "hw.h"
+#include "reg.h"
+#include "phy.h"
+
+void
+ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex, u32 freqIndex,
+ int regWrites)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ REG_WRITE_ARRAY(&ahp->ah_iniBB_RfGain, freqIndex, regWrites);
+}
+
+bool
+ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+ u32 channelSel = 0;
+ u32 bModeSynth = 0;
+ u32 aModeRefSel = 0;
+ u32 reg32 = 0;
+ u16 freq;
+ struct chan_centers centers;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+ freq = centers.synth_center;
+
+ if (freq < 4800) {
+ u32 txctl;
+
+ if (((freq - 2192) % 5) == 0) {
+ channelSel = ((freq - 672) * 2 - 3040) / 10;
+ bModeSynth = 0;
+ } else if (((freq - 2224) % 5) == 0) {
+ channelSel = ((freq - 704) * 2 - 3040) / 10;
+ bModeSynth = 1;
+ } else {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "%s: invalid channel %u MHz\n", __func__,
+ freq);
+ return false;
+ }
+
+ channelSel = (channelSel << 2) & 0xff;
+ channelSel = ath9k_hw_reverse_bits(channelSel, 8);
+
+ txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
+ if (freq == 2484) {
+
+ REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+ txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
+ } else {
+ REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+ txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
+ }
+
+ } else if ((freq % 20) == 0 && freq >= 5120) {
+ channelSel =
+ ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8);
+ aModeRefSel = ath9k_hw_reverse_bits(1, 2);
+ } else if ((freq % 10) == 0) {
+ channelSel =
+ ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8);
+ if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah))
+ aModeRefSel = ath9k_hw_reverse_bits(2, 2);
+ else
+ aModeRefSel = ath9k_hw_reverse_bits(1, 2);
+ } else if ((freq % 5) == 0) {
+ channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
+ aModeRefSel = ath9k_hw_reverse_bits(1, 2);
+ } else {
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ "%s: invalid channel %u MHz\n", __func__, freq);
+ return false;
+ }
+
+ reg32 =
+ (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
+ (1 << 5) | 0x1;
+
+ REG_WRITE(ah, AR_PHY(0x37), reg32);
+
+ ah->ah_curchan = chan;
+
+ AH5416(ah)->ah_curchanRadIndex = -1;
+
+ return true;
+}
+
+bool
+ath9k_hw_ar9280_set_channel(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ u16 bMode, fracMode, aModeRefSel = 0;
+ u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0;
+ struct chan_centers centers;
+ u32 refDivA = 24;
+
+ ath9k_hw_get_channel_centers(ah, chan, &centers);
+ freq = centers.synth_center;
+
+ reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL);
+ reg32 &= 0xc0000000;
+
+ if (freq < 4800) {
+ u32 txctl;
+
+ bMode = 1;
+ fracMode = 1;
+ aModeRefSel = 0;
+ channelSel = (freq * 0x10000) / 15;
+
+ txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
+ if (freq == 2484) {
+
+ REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+ txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
+ } else {
+ REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+ txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
+ }
+ } else {
+ bMode = 0;
+ fracMode = 0;
+
+ if ((freq % 20) == 0) {
+ aModeRefSel = 3;
+ } else if ((freq % 10) == 0) {
+ aModeRefSel = 2;
+ } else {
+ aModeRefSel = 0;
+
+ fracMode = 1;
+ refDivA = 1;
+ channelSel = (freq * 0x8000) / 15;
+
+ REG_RMW_FIELD(ah, AR_AN_SYNTH9,
+ AR_AN_SYNTH9_REFDIVA, refDivA);
+ }
+ if (!fracMode) {
+ ndiv = (freq * (refDivA >> aModeRefSel)) / 60;
+ channelSel = ndiv & 0x1ff;
+ channelFrac = (ndiv & 0xfffffe00) * 2;
+ channelSel = (channelSel << 17) | channelFrac;
+ }
+ }
+
+ reg32 = reg32 |
+ (bMode << 29) |
+ (fracMode << 28) | (aModeRefSel << 26) | (channelSel);
+
+ REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
+
+ ah->ah_curchan = chan;
+
+ AH5416(ah)->ah_curchanRadIndex = -1;
+
+ return true;
+}
+
+static void
+ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32,
+ u32 numBits, u32 firstBit,
+ u32 column)
+{
+ u32 tmp32, mask, arrayEntry, lastBit;
+ int32_t bitPosition, bitsLeft;
+
+ tmp32 = ath9k_hw_reverse_bits(reg32, numBits);
+ arrayEntry = (firstBit - 1) / 8;
+ bitPosition = (firstBit - 1) % 8;
+ bitsLeft = numBits;
+ while (bitsLeft > 0) {
+ lastBit = (bitPosition + bitsLeft > 8) ?
+ 8 : bitPosition + bitsLeft;
+ mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<
+ (column * 8);
+ rfBuf[arrayEntry] &= ~mask;
+ rfBuf[arrayEntry] |= ((tmp32 << bitPosition) <<
+ (column * 8)) & mask;
+ bitsLeft -= 8 - bitPosition;
+ tmp32 = tmp32 >> (8 - bitPosition);
+ bitPosition = 0;
+ arrayEntry++;
+ }
+}
+
+bool
+ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
+ u16 modesIndex)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ u32 eepMinorRev;
+ u32 ob5GHz = 0, db5GHz = 0;
+ u32 ob2GHz = 0, db2GHz = 0;
+ int regWrites = 0;
+
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ return true;
+
+ eepMinorRev = ath9k_hw_get_eeprom(ahp, EEP_MINOR_REV);
+
+ RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1);
+
+ RF_BANK_SETUP(ahp->ah_analogBank1Data, &ahp->ah_iniBank1, 1);
+
+ RF_BANK_SETUP(ahp->ah_analogBank2Data, &ahp->ah_iniBank2, 1);
+
+ RF_BANK_SETUP(ahp->ah_analogBank3Data, &ahp->ah_iniBank3,
+ modesIndex);
+ {
+ int i;
+ for (i = 0; i < ahp->ah_iniBank6TPC.ia_rows; i++) {
+ ahp->ah_analogBank6Data[i] =
+ INI_RA(&ahp->ah_iniBank6TPC, i, modesIndex);
+ }
+ }
+
+ if (eepMinorRev >= 2) {
+ if (IS_CHAN_2GHZ(chan)) {
+ ob2GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_2);
+ db2GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_2);
+ ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
+ ob2GHz, 3, 197, 0);
+ ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
+ db2GHz, 3, 194, 0);
+ } else {
+ ob5GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_5);
+ db5GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_5);
+ ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
+ ob5GHz, 3, 203, 0);
+ ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
+ db5GHz, 3, 200, 0);
+ }
+ }
+
+ RF_BANK_SETUP(ahp->ah_analogBank7Data, &ahp->ah_iniBank7, 1);
+
+ REG_WRITE_RF_ARRAY(&ahp->ah_iniBank0, ahp->ah_analogBank0Data,
+ regWrites);
+ REG_WRITE_RF_ARRAY(&ahp->ah_iniBank1, ahp->ah_analogBank1Data,
+ regWrites);
+ REG_WRITE_RF_ARRAY(&ahp->ah_iniBank2, ahp->ah_analogBank2Data,
+ regWrites);
+ REG_WRITE_RF_ARRAY(&ahp->ah_iniBank3, ahp->ah_analogBank3Data,
+ regWrites);
+ REG_WRITE_RF_ARRAY(&ahp->ah_iniBank6TPC, ahp->ah_analogBank6Data,
+ regWrites);
+ REG_WRITE_RF_ARRAY(&ahp->ah_iniBank7, ahp->ah_analogBank7Data,
+ regWrites);
+
+ return true;
+}
+
+void
+ath9k_hw_rfdetach(struct ath_hal *ah)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (ahp->ah_analogBank0Data != NULL) {
+ kfree(ahp->ah_analogBank0Data);
+ ahp->ah_analogBank0Data = NULL;
+ }
+ if (ahp->ah_analogBank1Data != NULL) {
+ kfree(ahp->ah_analogBank1Data);
+ ahp->ah_analogBank1Data = NULL;
+ }
+ if (ahp->ah_analogBank2Data != NULL) {
+ kfree(ahp->ah_analogBank2Data);
+ ahp->ah_analogBank2Data = NULL;
+ }
+ if (ahp->ah_analogBank3Data != NULL) {
+ kfree(ahp->ah_analogBank3Data);
+ ahp->ah_analogBank3Data = NULL;
+ }
+ if (ahp->ah_analogBank6Data != NULL) {
+ kfree(ahp->ah_analogBank6Data);
+ ahp->ah_analogBank6Data = NULL;
+ }
+ if (ahp->ah_analogBank6TPCData != NULL) {
+ kfree(ahp->ah_analogBank6TPCData);
+ ahp->ah_analogBank6TPCData = NULL;
+ }
+ if (ahp->ah_analogBank7Data != NULL) {
+ kfree(ahp->ah_analogBank7Data);
+ ahp->ah_analogBank7Data = NULL;
+ }
+ if (ahp->ah_addac5416_21 != NULL) {
+ kfree(ahp->ah_addac5416_21);
+ ahp->ah_addac5416_21 = NULL;
+ }
+ if (ahp->ah_bank6Temp != NULL) {
+ kfree(ahp->ah_bank6Temp);
+ ahp->ah_bank6Temp = NULL;
+ }
+}
+
+bool ath9k_hw_init_rf(struct ath_hal *ah, int *status)
+{
+ struct ath_hal_5416 *ahp = AH5416(ah);
+
+ if (!AR_SREV_9280_10_OR_LATER(ah)) {
+
+ ahp->ah_analogBank0Data =
+ kzalloc((sizeof(u32) *
+ ahp->ah_iniBank0.ia_rows), GFP_KERNEL);
+ ahp->ah_analogBank1Data =
+ kzalloc((sizeof(u32) *
+ ahp->ah_iniBank1.ia_rows), GFP_KERNEL);
+ ahp->ah_analogBank2Data =
+ kzalloc((sizeof(u32) *
+ ahp->ah_iniBank2.ia_rows), GFP_KERNEL);
+ ahp->ah_analogBank3Data =
+ kzalloc((sizeof(u32) *
+ ahp->ah_iniBank3.ia_rows), GFP_KERNEL);
+ ahp->ah_analogBank6Data =
+ kzalloc((sizeof(u32) *
+ ahp->ah_iniBank6.ia_rows), GFP_KERNEL);
+ ahp->ah_analogBank6TPCData =
+ kzalloc((sizeof(u32) *
+ ahp->ah_iniBank6TPC.ia_rows), GFP_KERNEL);
+ ahp->ah_analogBank7Data =
+ kzalloc((sizeof(u32) *
+ ahp->ah_iniBank7.ia_rows), GFP_KERNEL);
+
+ if (ahp->ah_analogBank0Data == NULL
+ || ahp->ah_analogBank1Data == NULL
+ || ahp->ah_analogBank2Data == NULL
+ || ahp->ah_analogBank3Data == NULL
+ || ahp->ah_analogBank6Data == NULL
+ || ahp->ah_analogBank6TPCData == NULL
+ || ahp->ah_analogBank7Data == NULL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "%s: cannot allocate RF banks\n",
+ __func__);
+ *status = -ENOMEM;
+ return false;
+ }
+
+ ahp->ah_addac5416_21 =
+ kzalloc((sizeof(u32) *
+ ahp->ah_iniAddac.ia_rows *
+ ahp->ah_iniAddac.ia_columns), GFP_KERNEL);
+ if (ahp->ah_addac5416_21 == NULL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "%s: cannot allocate ah_addac5416_21\n",
+ __func__);
+ *status = -ENOMEM;
+ return false;
+ }
+
+ ahp->ah_bank6Temp =
+ kzalloc((sizeof(u32) *
+ ahp->ah_iniBank6.ia_rows), GFP_KERNEL);
+ if (ahp->ah_bank6Temp == NULL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "%s: cannot allocate ah_bank6Temp\n",
+ __func__);
+ *status = -ENOMEM;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void
+ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+ int i, regWrites = 0;
+ struct ath_hal_5416 *ahp = AH5416(ah);
+ u32 bank6SelMask;
+ u32 *bank6Temp = ahp->ah_bank6Temp;
+
+ switch (ahp->ah_diversityControl) {
+ case ATH9K_ANT_FIXED_A:
+ bank6SelMask =
+ (ahp->
+ ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_0 :
+ REDUCE_CHAIN_1;
+ break;
+ case ATH9K_ANT_FIXED_B:
+ bank6SelMask =
+ (ahp->
+ ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_1 :
+ REDUCE_CHAIN_0;
+ break;
+ case ATH9K_ANT_VARIABLE:
+ return;
+ break;
+ default:
+ return;
+ break;
+ }
+
+ for (i = 0; i < ahp->ah_iniBank6.ia_rows; i++)
+ bank6Temp[i] = ahp->ah_analogBank6Data[i];
+
+ REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask);
+
+ ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0);
+ ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0);
+ ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0);
+ ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0);
+ ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0);
+ ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0);
+ ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0);
+ ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0);
+ ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0);
+
+ REG_WRITE_RF_ARRAY(&ahp->ah_iniBank6, bank6Temp, regWrites);
+
+ REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053);
+#ifdef ALTER_SWITCH
+ REG_WRITE(ah, PHY_SWITCH_CHAIN_0,
+ (REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38)
+ | ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38));
+#endif
+}
diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h
new file mode 100644
index 00000000000..0cd399a5344
--- /dev/null
+++ b/drivers/net/wireless/ath9k/phy.h
@@ -0,0 +1,543 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef PHY_H
+#define PHY_H
+
+bool ath9k_hw_ar9280_set_channel(struct ath_hal *ah,
+ struct ath9k_channel
+ *chan);
+bool ath9k_hw_set_channel(struct ath_hal *ah,
+ struct ath9k_channel *chan);
+void ath9k_hw_write_regs(struct ath_hal *ah, u32 modesIndex,
+ u32 freqIndex, int regWrites);
+bool ath9k_hw_set_rf_regs(struct ath_hal *ah,
+ struct ath9k_channel *chan,
+ u16 modesIndex);
+void ath9k_hw_decrease_chain_power(struct ath_hal *ah,
+ struct ath9k_channel *chan);
+bool ath9k_hw_init_rf(struct ath_hal *ah,
+ int *status);
+
+#define AR_PHY_BASE 0x9800
+#define AR_PHY(_n) (AR_PHY_BASE + ((_n)<<2))
+
+#define AR_PHY_TEST 0x9800
+#define PHY_AGC_CLR 0x10000000
+#define RFSILENT_BB 0x00002000
+
+#define AR_PHY_TURBO 0x9804
+#define AR_PHY_FC_TURBO_MODE 0x00000001
+#define AR_PHY_FC_TURBO_SHORT 0x00000002
+#define AR_PHY_FC_DYN2040_EN 0x00000004
+#define AR_PHY_FC_DYN2040_PRI_ONLY 0x00000008
+#define AR_PHY_FC_DYN2040_PRI_CH 0x00000010
+#define AR_PHY_FC_DYN2040_EXT_CH 0x00000020
+#define AR_PHY_FC_HT_EN 0x00000040
+#define AR_PHY_FC_SHORT_GI_40 0x00000080
+#define AR_PHY_FC_WALSH 0x00000100
+#define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200
+
+#define AR_PHY_TIMING2 0x9810
+#define AR_PHY_TIMING3 0x9814
+#define AR_PHY_TIMING3_DSC_MAN 0xFFFE0000
+#define AR_PHY_TIMING3_DSC_MAN_S 17
+#define AR_PHY_TIMING3_DSC_EXP 0x0001E000
+#define AR_PHY_TIMING3_DSC_EXP_S 13
+
+#define AR_PHY_CHIP_ID 0x9818
+#define AR_PHY_CHIP_ID_REV_0 0x80
+#define AR_PHY_CHIP_ID_REV_1 0x81
+#define AR_PHY_CHIP_ID_9160_REV_0 0xb0
+
+#define AR_PHY_ACTIVE 0x981C
+#define AR_PHY_ACTIVE_EN 0x00000001
+#define AR_PHY_ACTIVE_DIS 0x00000000
+
+#define AR_PHY_RF_CTL2 0x9824
+#define AR_PHY_TX_END_DATA_START 0x000000FF
+#define AR_PHY_TX_END_DATA_START_S 0
+#define AR_PHY_TX_END_PA_ON 0x0000FF00
+#define AR_PHY_TX_END_PA_ON_S 8
+
+#define AR_PHY_RF_CTL3 0x9828
+#define AR_PHY_TX_END_TO_A2_RX_ON 0x00FF0000
+#define AR_PHY_TX_END_TO_A2_RX_ON_S 16
+
+#define AR_PHY_ADC_CTL 0x982C
+#define AR_PHY_ADC_CTL_OFF_INBUFGAIN 0x00000003
+#define AR_PHY_ADC_CTL_OFF_INBUFGAIN_S 0
+#define AR_PHY_ADC_CTL_OFF_PWDDAC 0x00002000
+#define AR_PHY_ADC_CTL_OFF_PWDBANDGAP 0x00004000
+#define AR_PHY_ADC_CTL_OFF_PWDADC 0x00008000
+#define AR_PHY_ADC_CTL_ON_INBUFGAIN 0x00030000
+#define AR_PHY_ADC_CTL_ON_INBUFGAIN_S 16
+
+#define AR_PHY_ADC_SERIAL_CTL 0x9830
+#define AR_PHY_SEL_INTERNAL_ADDAC 0x00000000
+#define AR_PHY_SEL_EXTERNAL_RADIO 0x00000001
+
+#define AR_PHY_RF_CTL4 0x9834
+#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF 0xFF000000
+#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF_S 24
+#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF 0x00FF0000
+#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF_S 16
+#define AR_PHY_RF_CTL4_FRAME_XPAB_ON 0x0000FF00
+#define AR_PHY_RF_CTL4_FRAME_XPAB_ON_S 8
+#define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF
+#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0
+
+#define AR_PHY_SETTLING 0x9844
+#define AR_PHY_SETTLING_SWITCH 0x00003F80
+#define AR_PHY_SETTLING_SWITCH_S 7
+
+#define AR_PHY_RXGAIN 0x9848
+#define AR_PHY_RXGAIN_TXRX_ATTEN 0x0003F000
+#define AR_PHY_RXGAIN_TXRX_ATTEN_S 12
+#define AR_PHY_RXGAIN_TXRX_RF_MAX 0x007C0000
+#define AR_PHY_RXGAIN_TXRX_RF_MAX_S 18
+#define AR9280_PHY_RXGAIN_TXRX_ATTEN 0x00003F80
+#define AR9280_PHY_RXGAIN_TXRX_ATTEN_S 7
+#define AR9280_PHY_RXGAIN_TXRX_MARGIN 0x001FC000
+#define AR9280_PHY_RXGAIN_TXRX_MARGIN_S 14
+
+#define AR_PHY_DESIRED_SZ 0x9850
+#define AR_PHY_DESIRED_SZ_ADC 0x000000FF
+#define AR_PHY_DESIRED_SZ_ADC_S 0
+#define AR_PHY_DESIRED_SZ_PGA 0x0000FF00
+#define AR_PHY_DESIRED_SZ_PGA_S 8
+#define AR_PHY_DESIRED_SZ_TOT_DES 0x0FF00000
+#define AR_PHY_DESIRED_SZ_TOT_DES_S 20
+
+#define AR_PHY_FIND_SIG 0x9858
+#define AR_PHY_FIND_SIG_FIRSTEP 0x0003F000
+#define AR_PHY_FIND_SIG_FIRSTEP_S 12
+#define AR_PHY_FIND_SIG_FIRPWR 0x03FC0000
+#define AR_PHY_FIND_SIG_FIRPWR_S 18
+
+#define AR_PHY_AGC_CTL1 0x985C
+#define AR_PHY_AGC_CTL1_COARSE_LOW 0x00007F80
+#define AR_PHY_AGC_CTL1_COARSE_LOW_S 7
+#define AR_PHY_AGC_CTL1_COARSE_HIGH 0x003F8000
+#define AR_PHY_AGC_CTL1_COARSE_HIGH_S 15
+
+#define AR_PHY_AGC_CONTROL 0x9860
+#define AR_PHY_AGC_CONTROL_CAL 0x00000001
+#define AR_PHY_AGC_CONTROL_NF 0x00000002
+#define AR_PHY_AGC_CONTROL_ENABLE_NF 0x00008000
+#define AR_PHY_AGC_CONTROL_FLTR_CAL 0x00010000
+#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000
+
+#define AR_PHY_CCA 0x9864
+#define AR_PHY_MINCCA_PWR 0x0FF80000
+#define AR_PHY_MINCCA_PWR_S 19
+#define AR_PHY_CCA_THRESH62 0x0007F000
+#define AR_PHY_CCA_THRESH62_S 12
+#define AR9280_PHY_MINCCA_PWR 0x1FF00000
+#define AR9280_PHY_MINCCA_PWR_S 20
+#define AR9280_PHY_CCA_THRESH62 0x000FF000
+#define AR9280_PHY_CCA_THRESH62_S 12
+
+#define AR_PHY_SFCORR_LOW 0x986C
+#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW 0x00000001
+#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW 0x00003F00
+#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S 8
+#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW 0x001FC000
+#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S 14
+#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW 0x0FE00000
+#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S 21
+
+#define AR_PHY_SFCORR 0x9868
+#define AR_PHY_SFCORR_M2COUNT_THR 0x0000001F
+#define AR_PHY_SFCORR_M2COUNT_THR_S 0
+#define AR_PHY_SFCORR_M1_THRESH 0x00FE0000
+#define AR_PHY_SFCORR_M1_THRESH_S 17
+#define AR_PHY_SFCORR_M2_THRESH 0x7F000000
+#define AR_PHY_SFCORR_M2_THRESH_S 24
+
+#define AR_PHY_SLEEP_CTR_CONTROL 0x9870
+#define AR_PHY_SLEEP_CTR_LIMIT 0x9874
+#define AR_PHY_SYNTH_CONTROL 0x9874
+#define AR_PHY_SLEEP_SCAL 0x9878
+
+#define AR_PHY_PLL_CTL 0x987c
+#define AR_PHY_PLL_CTL_40 0xaa
+#define AR_PHY_PLL_CTL_40_5413 0x04
+#define AR_PHY_PLL_CTL_44 0xab
+#define AR_PHY_PLL_CTL_44_2133 0xeb
+#define AR_PHY_PLL_CTL_40_2133 0xea
+
+#define AR_PHY_RX_DELAY 0x9914
+#define AR_PHY_SEARCH_START_DELAY 0x9918
+#define AR_PHY_RX_DELAY_DELAY 0x00003FFF
+
+#define AR_PHY_TIMING_CTRL4(_i) (0x9920 + ((_i) << 12))
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01F
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S 0
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7E0
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S 5
+#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE 0x800
+#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xF000
+#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S 12
+#define AR_PHY_TIMING_CTRL4_DO_CAL 0x10000
+
+#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI 0x80000000
+#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER 0x40000000
+#define AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK 0x20000000
+#define AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK 0x10000000
+
+#define AR_PHY_TIMING5 0x9924
+#define AR_PHY_TIMING5_CYCPWR_THR1 0x000000FE
+#define AR_PHY_TIMING5_CYCPWR_THR1_S 1
+
+#define AR_PHY_POWER_TX_RATE1 0x9934
+#define AR_PHY_POWER_TX_RATE2 0x9938
+#define AR_PHY_POWER_TX_RATE_MAX 0x993c
+#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040
+
+#define AR_PHY_FRAME_CTL 0x9944
+#define AR_PHY_FRAME_CTL_TX_CLIP 0x00000038
+#define AR_PHY_FRAME_CTL_TX_CLIP_S 3
+
+#define AR_PHY_TXPWRADJ 0x994C
+#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA 0x00000FC0
+#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA_S 6
+#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX 0x00FC0000
+#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX_S 18
+
+#define AR_PHY_RADAR_EXT 0x9940
+#define AR_PHY_RADAR_EXT_ENA 0x00004000
+
+#define AR_PHY_RADAR_0 0x9954
+#define AR_PHY_RADAR_0_ENA 0x00000001
+#define AR_PHY_RADAR_0_FFT_ENA 0x80000000
+#define AR_PHY_RADAR_0_INBAND 0x0000003e
+#define AR_PHY_RADAR_0_INBAND_S 1
+#define AR_PHY_RADAR_0_PRSSI 0x00000FC0
+#define AR_PHY_RADAR_0_PRSSI_S 6
+#define AR_PHY_RADAR_0_HEIGHT 0x0003F000
+#define AR_PHY_RADAR_0_HEIGHT_S 12
+#define AR_PHY_RADAR_0_RRSSI 0x00FC0000
+#define AR_PHY_RADAR_0_RRSSI_S 18
+#define AR_PHY_RADAR_0_FIRPWR 0x7F000000
+#define AR_PHY_RADAR_0_FIRPWR_S 24
+
+#define AR_PHY_RADAR_1 0x9958
+#define AR_PHY_RADAR_1_RELPWR_ENA 0x00800000
+#define AR_PHY_RADAR_1_USE_FIR128 0x00400000
+#define AR_PHY_RADAR_1_RELPWR_THRESH 0x003F0000
+#define AR_PHY_RADAR_1_RELPWR_THRESH_S 16
+#define AR_PHY_RADAR_1_BLOCK_CHECK 0x00008000
+#define AR_PHY_RADAR_1_MAX_RRSSI 0x00004000
+#define AR_PHY_RADAR_1_RELSTEP_CHECK 0x00002000
+#define AR_PHY_RADAR_1_RELSTEP_THRESH 0x00001F00
+#define AR_PHY_RADAR_1_RELSTEP_THRESH_S 8
+#define AR_PHY_RADAR_1_MAXLEN 0x000000FF
+#define AR_PHY_RADAR_1_MAXLEN_S 0
+
+#define AR_PHY_SWITCH_CHAIN_0 0x9960
+#define AR_PHY_SWITCH_COM 0x9964
+
+#define AR_PHY_SIGMA_DELTA 0x996C
+#define AR_PHY_SIGMA_DELTA_ADC_SEL 0x00000003
+#define AR_PHY_SIGMA_DELTA_ADC_SEL_S 0
+#define AR_PHY_SIGMA_DELTA_FILT2 0x000000F8
+#define AR_PHY_SIGMA_DELTA_FILT2_S 3
+#define AR_PHY_SIGMA_DELTA_FILT1 0x00001F00
+#define AR_PHY_SIGMA_DELTA_FILT1_S 8
+#define AR_PHY_SIGMA_DELTA_ADC_CLIP 0x01FFE000
+#define AR_PHY_SIGMA_DELTA_ADC_CLIP_S 13
+
+#define AR_PHY_RESTART 0x9970
+#define AR_PHY_RESTART_DIV_GC 0x001C0000
+#define AR_PHY_RESTART_DIV_GC_S 18
+
+#define AR_PHY_RFBUS_REQ 0x997C
+#define AR_PHY_RFBUS_REQ_EN 0x00000001
+
+#define AR_PHY_TIMING7 0x9980
+#define AR_PHY_TIMING8 0x9984
+#define AR_PHY_TIMING8_PILOT_MASK_2 0x000FFFFF
+#define AR_PHY_TIMING8_PILOT_MASK_2_S 0
+
+#define AR_PHY_BIN_MASK2_1 0x9988
+#define AR_PHY_BIN_MASK2_2 0x998c
+#define AR_PHY_BIN_MASK2_3 0x9990
+#define AR_PHY_BIN_MASK2_4 0x9994
+
+#define AR_PHY_BIN_MASK_1 0x9900
+#define AR_PHY_BIN_MASK_2 0x9904
+#define AR_PHY_BIN_MASK_3 0x9908
+
+#define AR_PHY_MASK_CTL 0x990c
+
+#define AR_PHY_BIN_MASK2_4_MASK_4 0x00003FFF
+#define AR_PHY_BIN_MASK2_4_MASK_4_S 0
+
+#define AR_PHY_TIMING9 0x9998
+#define AR_PHY_TIMING10 0x999c
+#define AR_PHY_TIMING10_PILOT_MASK_2 0x000FFFFF
+#define AR_PHY_TIMING10_PILOT_MASK_2_S 0
+
+#define AR_PHY_TIMING11 0x99a0
+#define AR_PHY_TIMING11_SPUR_DELTA_PHASE 0x000FFFFF
+#define AR_PHY_TIMING11_SPUR_DELTA_PHASE_S 0
+#define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000
+#define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20
+#define AR_PHY_TIMING11_USE_SPUR_IN_AGC 0x40000000
+#define AR_PHY_TIMING11_USE_SPUR_IN_SELFCOR 0x80000000
+
+#define AR_PHY_RX_CHAINMASK 0x99a4
+#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12))
+#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000
+#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
+#define AR_PHY_MULTICHAIN_GAIN_CTL 0x99ac
+
+#define AR_PHY_EXT_CCA0 0x99b8
+#define AR_PHY_EXT_CCA0_THRESH62 0x000000FF
+#define AR_PHY_EXT_CCA0_THRESH62_S 0
+
+#define AR_PHY_EXT_CCA 0x99bc
+#define AR_PHY_EXT_CCA_CYCPWR_THR1 0x0000FE00
+#define AR_PHY_EXT_CCA_CYCPWR_THR1_S 9
+#define AR_PHY_EXT_CCA_THRESH62 0x007F0000
+#define AR_PHY_EXT_CCA_THRESH62_S 16
+#define AR_PHY_EXT_MINCCA_PWR 0xFF800000
+#define AR_PHY_EXT_MINCCA_PWR_S 23
+#define AR9280_PHY_EXT_MINCCA_PWR 0x01FF0000
+#define AR9280_PHY_EXT_MINCCA_PWR_S 16
+
+#define AR_PHY_SFCORR_EXT 0x99c0
+#define AR_PHY_SFCORR_EXT_M1_THRESH 0x0000007F
+#define AR_PHY_SFCORR_EXT_M1_THRESH_S 0
+#define AR_PHY_SFCORR_EXT_M2_THRESH 0x00003F80
+#define AR_PHY_SFCORR_EXT_M2_THRESH_S 7
+#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW 0x001FC000
+#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14
+#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW 0x0FE00000
+#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21
+#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S 28
+
+#define AR_PHY_HALFGI 0x99D0
+#define AR_PHY_HALFGI_DSC_MAN 0x0007FFF0
+#define AR_PHY_HALFGI_DSC_MAN_S 4
+#define AR_PHY_HALFGI_DSC_EXP 0x0000000F
+#define AR_PHY_HALFGI_DSC_EXP_S 0
+
+#define AR_PHY_CHAN_INFO_MEMORY 0x99DC
+#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK 0x0001
+
+#define AR_PHY_HEAVY_CLIP_ENABLE 0x99E0
+
+#define AR_PHY_M_SLEEP 0x99f0
+#define AR_PHY_REFCLKDLY 0x99f4
+#define AR_PHY_REFCLKPD 0x99f8
+
+#define AR_PHY_CALMODE 0x99f0
+
+#define AR_PHY_CALMODE_IQ 0x00000000
+#define AR_PHY_CALMODE_ADC_GAIN 0x00000001
+#define AR_PHY_CALMODE_ADC_DC_PER 0x00000002
+#define AR_PHY_CALMODE_ADC_DC_INIT 0x00000003
+
+#define AR_PHY_CAL_MEAS_0(_i) (0x9c10 + ((_i) << 12))
+#define AR_PHY_CAL_MEAS_1(_i) (0x9c14 + ((_i) << 12))
+#define AR_PHY_CAL_MEAS_2(_i) (0x9c18 + ((_i) << 12))
+#define AR_PHY_CAL_MEAS_3(_i) (0x9c1c + ((_i) << 12))
+
+#define AR_PHY_CURRENT_RSSI 0x9c1c
+#define AR9280_PHY_CURRENT_RSSI 0x9c3c
+
+#define AR_PHY_RFBUS_GRANT 0x9C20
+#define AR_PHY_RFBUS_GRANT_EN 0x00000001
+
+#define AR_PHY_CHAN_INFO_GAIN_DIFF 0x9CF4
+#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320
+
+#define AR_PHY_CHAN_INFO_GAIN 0x9CFC
+
+#define AR_PHY_MODE 0xA200
+#define AR_PHY_MODE_AR2133 0x08
+#define AR_PHY_MODE_AR5111 0x00
+#define AR_PHY_MODE_AR5112 0x08
+#define AR_PHY_MODE_DYNAMIC 0x04
+#define AR_PHY_MODE_RF2GHZ 0x02
+#define AR_PHY_MODE_RF5GHZ 0x00
+#define AR_PHY_MODE_CCK 0x01
+#define AR_PHY_MODE_OFDM 0x00
+#define AR_PHY_MODE_DYN_CCK_DISABLE 0x100
+
+#define AR_PHY_CCK_TX_CTRL 0xA204
+#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010
+
+#define AR_PHY_CCK_DETECT 0xA208
+#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F
+#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S 0
+/* [12:6] settling time for antenna switch */
+#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME 0x00001FC0
+#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S 6
+#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV 0x2000
+
+#define AR_PHY_GAIN_2GHZ 0xA20C
+#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN 0x00FC0000
+#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN_S 18
+#define AR_PHY_GAIN_2GHZ_BSW_MARGIN 0x00003C00
+#define AR_PHY_GAIN_2GHZ_BSW_MARGIN_S 10
+#define AR_PHY_GAIN_2GHZ_BSW_ATTEN 0x0000001F
+#define AR_PHY_GAIN_2GHZ_BSW_ATTEN_S 0
+
+#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN 0x003E0000
+#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN_S 17
+#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN 0x0001F000
+#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN_S 12
+#define AR_PHY_GAIN_2GHZ_XATTEN2_DB 0x00000FC0
+#define AR_PHY_GAIN_2GHZ_XATTEN2_DB_S 6
+#define AR_PHY_GAIN_2GHZ_XATTEN1_DB 0x0000003F
+#define AR_PHY_GAIN_2GHZ_XATTEN1_DB_S 0
+
+#define AR_PHY_CCK_RXCTRL4 0xA21C
+#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT 0x01F80000
+#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19
+
+#define AR_PHY_DAG_CTRLCCK 0xA228
+#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR 0x00000200
+#define AR_PHY_DAG_CTRLCCK_RSSI_THR 0x0001FC00
+#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S 10
+
+#define AR_PHY_FORCE_CLKEN_CCK 0xA22C
+#define AR_PHY_FORCE_CLKEN_CCK_MRC_MUX 0x00000040
+
+#define AR_PHY_POWER_TX_RATE3 0xA234
+#define AR_PHY_POWER_TX_RATE4 0xA238
+
+#define AR_PHY_SCRM_SEQ_XR 0xA23C
+#define AR_PHY_HEADER_DETECT_XR 0xA240
+#define AR_PHY_CHIRP_DETECTED_XR 0xA244
+#define AR_PHY_BLUETOOTH 0xA254
+
+#define AR_PHY_TPCRG1 0xA258
+#define AR_PHY_TPCRG1_NUM_PD_GAIN 0x0000c000
+#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14
+
+#define AR_PHY_TPCRG1_PD_GAIN_1 0x00030000
+#define AR_PHY_TPCRG1_PD_GAIN_1_S 16
+#define AR_PHY_TPCRG1_PD_GAIN_2 0x000C0000
+#define AR_PHY_TPCRG1_PD_GAIN_2_S 18
+#define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000
+#define AR_PHY_TPCRG1_PD_GAIN_3_S 20
+
+#define AR_PHY_VIT_MASK2_M_46_61 0xa3a0
+#define AR_PHY_MASK2_M_31_45 0xa3a4
+#define AR_PHY_MASK2_M_16_30 0xa3a8
+#define AR_PHY_MASK2_M_00_15 0xa3ac
+#define AR_PHY_MASK2_P_15_01 0xa3b8
+#define AR_PHY_MASK2_P_30_16 0xa3bc
+#define AR_PHY_MASK2_P_45_31 0xa3c0
+#define AR_PHY_MASK2_P_61_45 0xa3c4
+#define AR_PHY_SPUR_REG 0x994c
+
+#define AR_PHY_SPUR_REG_MASK_RATE_CNTL (0xFF << 18)
+#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S 18
+
+#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM 0x20000
+#define AR_PHY_SPUR_REG_MASK_RATE_SELECT (0xFF << 9)
+#define AR_PHY_SPUR_REG_MASK_RATE_SELECT_S 9
+#define AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100
+#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH 0x7F
+#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S 0
+
+#define AR_PHY_PILOT_MASK_01_30 0xa3b0
+#define AR_PHY_PILOT_MASK_31_60 0xa3b4
+
+#define AR_PHY_CHANNEL_MASK_01_30 0x99d4
+#define AR_PHY_CHANNEL_MASK_31_60 0x99d8
+
+#define AR_PHY_ANALOG_SWAP 0xa268
+#define AR_PHY_SWAP_ALT_CHAIN 0x00000040
+
+#define AR_PHY_TPCRG5 0xA26C
+#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP 0x0000000F
+#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S 0
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1 0x000003F0
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S 4
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2 0x0000FC00
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S 10
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3 0x003F0000
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S 16
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0FC00000
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22
+
+#define AR_PHY_POWER_TX_RATE5 0xA38C
+#define AR_PHY_POWER_TX_RATE6 0xA390
+
+#define AR_PHY_CAL_CHAINMASK 0xA39C
+
+#define AR_PHY_POWER_TX_SUB 0xA3C8
+#define AR_PHY_POWER_TX_RATE7 0xA3CC
+#define AR_PHY_POWER_TX_RATE8 0xA3D0
+#define AR_PHY_POWER_TX_RATE9 0xA3D4
+
+#define AR_PHY_XPA_CFG 0xA3D8
+#define AR_PHY_FORCE_XPA_CFG 0x000000001
+#define AR_PHY_FORCE_XPA_CFG_S 0
+
+#define AR_PHY_CH1_CCA 0xa864
+#define AR_PHY_CH1_MINCCA_PWR 0x0FF80000
+#define AR_PHY_CH1_MINCCA_PWR_S 19
+#define AR9280_PHY_CH1_MINCCA_PWR 0x1FF00000
+#define AR9280_PHY_CH1_MINCCA_PWR_S 20
+
+#define AR_PHY_CH2_CCA 0xb864
+#define AR_PHY_CH2_MINCCA_PWR 0x0FF80000
+#define AR_PHY_CH2_MINCCA_PWR_S 19
+
+#define AR_PHY_CH1_EXT_CCA 0xa9bc
+#define AR_PHY_CH1_EXT_MINCCA_PWR 0xFF800000
+#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23
+#define AR9280_PHY_CH1_EXT_MINCCA_PWR 0x01FF0000
+#define AR9280_PHY_CH1_EXT_MINCCA_PWR_S 16
+
+#define AR_PHY_CH2_EXT_CCA 0xb9bc
+#define AR_PHY_CH2_EXT_MINCCA_PWR 0xFF800000
+#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23
+
+#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do { \
+ int r; \
+ for (r = 0; r < ((iniarray)->ia_rows); r++) { \
+ REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \
+ DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, \
+ "RF 0x%x V 0x%x\n", \
+ INI_RA((iniarray), r, 0), (regData)[r]); \
+ DO_DELAY(regWr); \
+ } \
+ } while (0)
+
+#define ATH9K_KEY_XOR 0xaa
+
+#define ATH9K_IS_MIC_ENABLED(ah) \
+ (AH5416(ah)->ah_staId1Defaults & AR_STA_ID1_CRPT_MIC_ENABLE)
+
+#define ANTSWAP_AB 0x0001
+#define REDUCE_CHAIN_0 0x00000050
+#define REDUCE_CHAIN_1 0x00000051
+
+#define RF_BANK_SETUP(_bank, _iniarray, _col) do { \
+ int i; \
+ for (i = 0; i < (_iniarray)->ia_rows; i++) \
+ (_bank)[i] = INI_RA((_iniarray), i, _col);; \
+ } while (0)
+
+#endif
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
new file mode 100644
index 00000000000..73c460ad355
--- /dev/null
+++ b/drivers/net/wireless/ath9k/rc.c
@@ -0,0 +1,2126 @@
+/*
+ * Copyright (c) 2004 Video54 Technologies, Inc.
+ * Copyright (c) 2004-2008 Atheros Communications, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Atheros rate control algorithm
+ */
+
+#include "core.h"
+#include "../net/mac80211/rate.h"
+
+static u32 tx_triglevel_max;
+
+static struct ath_rate_table ar5416_11na_ratetable = {
+ 42,
+ {
+ { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ 5400, 0x0b, 0x00, 12,
+ 0, 2, 1, 0, 0, 0, 0, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+ 7800, 0x0f, 0x00, 18,
+ 0, 3, 1, 1, 1, 1, 1, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ 10000, 0x0a, 0x00, 24,
+ 2, 4, 2, 2, 2, 2, 2, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ 13900, 0x0e, 0x00, 36,
+ 2, 6, 2, 3, 3, 3, 3, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ 17300, 0x09, 0x00, 48,
+ 4, 10, 3, 4, 4, 4, 4, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ 23000, 0x0d, 0x00, 72,
+ 4, 14, 3, 5, 5, 5, 5, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ 27400, 0x08, 0x00, 96,
+ 4, 20, 3, 6, 6, 6, 6, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ 29300, 0x0c, 0x00, 108,
+ 4, 23, 3, 7, 7, 7, 7, 0 },
+ { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */
+ 6400, 0x80, 0x00, 0,
+ 0, 2, 3, 8, 24, 8, 24, 3216 },
+ { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */
+ 12700, 0x81, 0x00, 1,
+ 2, 4, 3, 9, 25, 9, 25, 6434 },
+ { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */
+ 18800, 0x82, 0x00, 2,
+ 2, 6, 3, 10, 26, 10, 26, 9650 },
+ { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */
+ 25000, 0x83, 0x00, 3,
+ 4, 10, 3, 11, 27, 11, 27, 12868 },
+ { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */
+ 36700, 0x84, 0x00, 4,
+ 4, 14, 3, 12, 28, 12, 28, 19304 },
+ { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */
+ 48100, 0x85, 0x00, 5,
+ 4, 20, 3, 13, 29, 13, 29, 25740 },
+ { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */
+ 53500, 0x86, 0x00, 6,
+ 4, 23, 3, 14, 30, 14, 30, 28956 },
+ { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */
+ 59000, 0x87, 0x00, 7,
+ 4, 25, 3, 15, 31, 15, 32, 32180 },
+ { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */
+ 12700, 0x88, 0x00,
+ 8, 0, 2, 3, 16, 33, 16, 33, 6430 },
+ { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */
+ 24800, 0x89, 0x00, 9,
+ 2, 4, 3, 17, 34, 17, 34, 12860 },
+ { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */
+ 36600, 0x8a, 0x00, 10,
+ 2, 6, 3, 18, 35, 18, 35, 19300 },
+ { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */
+ 48100, 0x8b, 0x00, 11,
+ 4, 10, 3, 19, 36, 19, 36, 25736 },
+ { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */
+ 69500, 0x8c, 0x00, 12,
+ 4, 14, 3, 20, 37, 20, 37, 38600 },
+ { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */
+ 89500, 0x8d, 0x00, 13,
+ 4, 20, 3, 21, 38, 21, 38, 51472 },
+ { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */
+ 98900, 0x8e, 0x00, 14,
+ 4, 23, 3, 22, 39, 22, 39, 57890 },
+ { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */
+ 108300, 0x8f, 0x00, 15,
+ 4, 25, 3, 23, 40, 23, 41, 64320 },
+ { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */
+ 13200, 0x80, 0x00, 0,
+ 0, 2, 3, 8, 24, 24, 24, 6684 },
+ { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */
+ 25900, 0x81, 0x00, 1,
+ 2, 4, 3, 9, 25, 25, 25, 13368 },
+ { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */
+ 38600, 0x82, 0x00, 2,
+ 2, 6, 3, 10, 26, 26, 26, 20052 },
+ { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */
+ 49800, 0x83, 0x00, 3,
+ 4, 10, 3, 11, 27, 27, 27, 26738 },
+ { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */
+ 72200, 0x84, 0x00, 4,
+ 4, 14, 3, 12, 28, 28, 28, 40104 },
+ { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */
+ 92900, 0x85, 0x00, 5,
+ 4, 20, 3, 13, 29, 29, 29, 53476 },
+ { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */
+ 102700, 0x86, 0x00, 6,
+ 4, 23, 3, 14, 30, 30, 30, 60156 },
+ { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */
+ 112000, 0x87, 0x00, 7,
+ 4, 25, 3, 15, 31, 32, 32, 66840 },
+ { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
+ 122000, 0x87, 0x00, 7,
+ 4, 25, 3, 15, 31, 32, 32, 74200 },
+ { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */
+ 25800, 0x88, 0x00, 8,
+ 0, 2, 3, 16, 33, 33, 33, 13360 },
+ { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */
+ 49800, 0x89, 0x00, 9,
+ 2, 4, 3, 17, 34, 34, 34, 26720 },
+ { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */
+ 71900, 0x8a, 0x00, 10,
+ 2, 6, 3, 18, 35, 35, 35, 40080 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */
+ 92500, 0x8b, 0x00, 11,
+ 4, 10, 3, 19, 36, 36, 36, 53440 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */
+ 130300, 0x8c, 0x00, 12,
+ 4, 14, 3, 20, 37, 37, 37, 80160 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */
+ 162800, 0x8d, 0x00, 13,
+ 4, 20, 3, 21, 38, 38, 38, 106880 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */
+ 178200, 0x8e, 0x00, 14,
+ 4, 23, 3, 22, 39, 39, 39, 120240 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */
+ 192100, 0x8f, 0x00, 15,
+ 4, 25, 3, 23, 40, 41, 41, 133600 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
+ 207000, 0x8f, 0x00, 15,
+ 4, 25, 3, 23, 40, 41, 41, 148400 },
+ },
+ 50, /* probe interval */
+ 50, /* rssi reduce interval */
+ WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
+};
+
+/* TRUE_ALL - valid for 20/40/Legacy,
+ * TRUE - Legacy only,
+ * TRUE_20 - HT 20 only,
+ * TRUE_40 - HT 40 only */
+
+/* 4ms frame limit not used for NG mode. The values filled
+ * for HT are the 64K max aggregate limit */
+
+static struct ath_rate_table ar5416_11ng_ratetable = {
+ 46,
+ {
+ { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 1000, /* 1 Mb */
+ 900, 0x1b, 0x00, 2,
+ 0, 0, 1, 0, 0, 0, 0, 0 },
+ { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 2000, /* 2 Mb */
+ 1900, 0x1a, 0x04, 4,
+ 1, 1, 1, 1, 1, 1, 1, 0 },
+ { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+ 4900, 0x19, 0x04, 11,
+ 2, 2, 2, 2, 2, 2, 2, 0 },
+ { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 11000, /* 11 Mb */
+ 8100, 0x18, 0x04, 22,
+ 3, 3, 2, 3, 3, 3, 3, 0 },
+ { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ 5400, 0x0b, 0x00, 12,
+ 4, 2, 1, 4, 4, 4, 4, 0 },
+ { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+ 7800, 0x0f, 0x00, 18,
+ 4, 3, 1, 5, 5, 5, 5, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ 10100, 0x0a, 0x00, 24,
+ 6, 4, 1, 6, 6, 6, 6, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ 14100, 0x0e, 0x00, 36,
+ 6, 6, 2, 7, 7, 7, 7, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ 17700, 0x09, 0x00, 48,
+ 8, 10, 3, 8, 8, 8, 8, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ 23700, 0x0d, 0x00, 72,
+ 8, 14, 3, 9, 9, 9, 9, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ 27400, 0x08, 0x00, 96,
+ 8, 20, 3, 10, 10, 10, 10, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ 30900, 0x0c, 0x00, 108,
+ 8, 23, 3, 11, 11, 11, 11, 0 },
+ { FALSE, FALSE, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */
+ 6400, 0x80, 0x00, 0,
+ 4, 2, 3, 12, 28, 12, 28, 3216 },
+ { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */
+ 12700, 0x81, 0x00, 1,
+ 6, 4, 3, 13, 29, 13, 29, 6434 },
+ { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */
+ 18800, 0x82, 0x00, 2,
+ 6, 6, 3, 14, 30, 14, 30, 9650 },
+ { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */
+ 25000, 0x83, 0x00, 3,
+ 8, 10, 3, 15, 31, 15, 31, 12868 },
+ { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */
+ 36700, 0x84, 0x00, 4,
+ 8, 14, 3, 16, 32, 16, 32, 19304 },
+ { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */
+ 48100, 0x85, 0x00, 5,
+ 8, 20, 3, 17, 33, 17, 33, 25740 },
+ { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */
+ 53500, 0x86, 0x00, 6,
+ 8, 23, 3, 18, 34, 18, 34, 28956 },
+ { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */
+ 59000, 0x87, 0x00, 7,
+ 8, 25, 3, 19, 35, 19, 36, 32180 },
+ { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */
+ 12700, 0x88, 0x00, 8,
+ 4, 2, 3, 20, 37, 20, 37, 6430 },
+ { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */
+ 24800, 0x89, 0x00, 9,
+ 6, 4, 3, 21, 38, 21, 38, 12860 },
+ { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */
+ 36600, 0x8a, 0x00, 10,
+ 6, 6, 3, 22, 39, 22, 39, 19300 },
+ { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */
+ 48100, 0x8b, 0x00, 11,
+ 8, 10, 3, 23, 40, 23, 40, 25736 },
+ { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */
+ 69500, 0x8c, 0x00, 12,
+ 8, 14, 3, 24, 41, 24, 41, 38600 },
+ { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */
+ 89500, 0x8d, 0x00, 13,
+ 8, 20, 3, 25, 42, 25, 42, 51472 },
+ { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */
+ 98900, 0x8e, 0x00, 14,
+ 8, 23, 3, 26, 43, 26, 44, 57890 },
+ { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */
+ 108300, 0x8f, 0x00, 15,
+ 8, 25, 3, 27, 44, 27, 45, 64320 },
+ { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */
+ 13200, 0x80, 0x00, 0,
+ 8, 2, 3, 12, 28, 28, 28, 6684 },
+ { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */
+ 25900, 0x81, 0x00, 1,
+ 8, 4, 3, 13, 29, 29, 29, 13368 },
+ { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */
+ 38600, 0x82, 0x00, 2,
+ 8, 6, 3, 14, 30, 30, 30, 20052 },
+ { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */
+ 49800, 0x83, 0x00, 3,
+ 8, 10, 3, 15, 31, 31, 31, 26738 },
+ { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */
+ 72200, 0x84, 0x00, 4,
+ 8, 14, 3, 16, 32, 32, 32, 40104 },
+ { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */
+ 92900, 0x85, 0x00, 5,
+ 8, 20, 3, 17, 33, 33, 33, 53476 },
+ { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */
+ 102700, 0x86, 0x00, 6,
+ 8, 23, 3, 18, 34, 34, 34, 60156 },
+ { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */
+ 112000, 0x87, 0x00, 7,
+ 8, 23, 3, 19, 35, 36, 36, 66840 },
+ { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
+ 122000, 0x87, 0x00, 7,
+ 8, 25, 3, 19, 35, 36, 36, 74200 },
+ { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */
+ 25800, 0x88, 0x00, 8,
+ 8, 2, 3, 20, 37, 37, 37, 13360 },
+ { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */
+ 49800, 0x89, 0x00, 9,
+ 8, 4, 3, 21, 38, 38, 38, 26720 },
+ { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */
+ 71900, 0x8a, 0x00, 10,
+ 8, 6, 3, 22, 39, 39, 39, 40080 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */
+ 92500, 0x8b, 0x00, 11,
+ 8, 10, 3, 23, 40, 40, 40, 53440 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */
+ 130300, 0x8c, 0x00, 12,
+ 8, 14, 3, 24, 41, 41, 41, 80160 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */
+ 162800, 0x8d, 0x00, 13,
+ 8, 20, 3, 25, 42, 42, 42, 106880 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */
+ 178200, 0x8e, 0x00, 14,
+ 8, 23, 3, 26, 43, 43, 43, 120240 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */
+ 192100, 0x8f, 0x00, 15,
+ 8, 23, 3, 27, 44, 45, 45, 133600 },
+ { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
+ 207000, 0x8f, 0x00, 15,
+ 8, 25, 3, 27, 44, 45, 45, 148400 },
+ },
+ 50, /* probe interval */
+ 50, /* rssi reduce interval */
+ WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
+};
+
+static struct ath_rate_table ar5416_11a_ratetable = {
+ 8,
+ {
+ { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ 5400, 0x0b, 0x00, (0x80|12),
+ 0, 2, 1, 0, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+ 7800, 0x0f, 0x00, 18,
+ 0, 3, 1, 1, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ 10000, 0x0a, 0x00, (0x80|24),
+ 2, 4, 2, 2, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ 13900, 0x0e, 0x00, 36,
+ 2, 6, 2, 3, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ 17300, 0x09, 0x00, (0x80|48),
+ 4, 10, 3, 4, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ 23000, 0x0d, 0x00, 72,
+ 4, 14, 3, 5, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ 27400, 0x08, 0x00, 96,
+ 4, 19, 3, 6, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ 29300, 0x0c, 0x00, 108,
+ 4, 23, 3, 7, 0 },
+ },
+ 50, /* probe interval */
+ 50, /* rssi reduce interval */
+ 0, /* Phy rates allowed initially */
+};
+
+static struct ath_rate_table ar5416_11a_ratetable_Half = {
+ 8,
+ {
+ { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 6 Mb */
+ 2700, 0x0b, 0x00, (0x80|6),
+ 0, 2, 1, 0, 0},
+ { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 9 Mb */
+ 3900, 0x0f, 0x00, 9,
+ 0, 3, 1, 1, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 12 Mb */
+ 5000, 0x0a, 0x00, (0x80|12),
+ 2, 4, 2, 2, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 18 Mb */
+ 6950, 0x0e, 0x00, 18,
+ 2, 6, 2, 3, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 24 Mb */
+ 8650, 0x09, 0x00, (0x80|24),
+ 4, 10, 3, 4, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 36 Mb */
+ 11500, 0x0d, 0x00, 36,
+ 4, 14, 3, 5, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 48 Mb */
+ 13700, 0x08, 0x00, 48,
+ 4, 19, 3, 6, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 27000, /* 54 Mb */
+ 14650, 0x0c, 0x00, 54,
+ 4, 23, 3, 7, 0 },
+ },
+ 50, /* probe interval */
+ 50, /* rssi reduce interval */
+ 0, /* Phy rates allowed initially */
+};
+
+static struct ath_rate_table ar5416_11a_ratetable_Quarter = {
+ 8,
+ {
+ { TRUE, TRUE, WLAN_PHY_OFDM, 1500, /* 6 Mb */
+ 1350, 0x0b, 0x00, (0x80|3),
+ 0, 2, 1, 0, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 2250, /* 9 Mb */
+ 1950, 0x0f, 0x00, 4,
+ 0, 3, 1, 1, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 12 Mb */
+ 2500, 0x0a, 0x00, (0x80|6),
+ 2, 4, 2, 2, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 18 Mb */
+ 3475, 0x0e, 0x00, 9,
+ 2, 6, 2, 3, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 25 Mb */
+ 4325, 0x09, 0x00, (0x80|12),
+ 4, 10, 3, 4, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 36 Mb */
+ 5750, 0x0d, 0x00, 18,
+ 4, 14, 3, 5, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 48 Mb */
+ 6850, 0x08, 0x00, 24,
+ 4, 19, 3, 6, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 13500, /* 54 Mb */
+ 7325, 0x0c, 0x00, 27,
+ 4, 23, 3, 7, 0 },
+ },
+ 50, /* probe interval */
+ 50, /* rssi reduce interval */
+ 0, /* Phy rates allowed initially */
+};
+
+static struct ath_rate_table ar5416_11g_ratetable = {
+ 12,
+ {
+ { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */
+ 900, 0x1b, 0x00, 2,
+ 0, 0, 1, 0, 0 },
+ { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */
+ 1900, 0x1a, 0x04, 4,
+ 1, 1, 1, 1, 0 },
+ { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+ 4900, 0x19, 0x04, 11,
+ 2, 2, 2, 2, 0 },
+ { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */
+ 8100, 0x18, 0x04, 22,
+ 3, 3, 2, 3, 0 },
+ { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */
+ 5400, 0x0b, 0x00, 12,
+ 4, 2, 1, 4, 0 },
+ { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */
+ 7800, 0x0f, 0x00, 18,
+ 4, 3, 1, 5, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */
+ 10000, 0x0a, 0x00, 24,
+ 6, 4, 1, 6, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */
+ 13900, 0x0e, 0x00, 36,
+ 6, 6, 2, 7, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */
+ 17300, 0x09, 0x00, 48,
+ 8, 10, 3, 8, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */
+ 23000, 0x0d, 0x00, 72,
+ 8, 14, 3, 9, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */
+ 27400, 0x08, 0x00, 96,
+ 8, 19, 3, 10, 0 },
+ { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */
+ 29300, 0x0c, 0x00, 108,
+ 8, 23, 3, 11, 0 },
+ },
+ 50, /* probe interval */
+ 50, /* rssi reduce interval */
+ 0, /* Phy rates allowed initially */
+};
+
+static struct ath_rate_table ar5416_11b_ratetable = {
+ 4,
+ {
+ { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */
+ 900, 0x1b, 0x00, (0x80|2),
+ 0, 0, 1, 0, 0 },
+ { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */
+ 1800, 0x1a, 0x04, (0x80|4),
+ 1, 1, 1, 1, 0 },
+ { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */
+ 4300, 0x19, 0x04, (0x80|11),
+ 1, 2, 2, 2, 0 },
+ { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */
+ 7100, 0x18, 0x04, (0x80|22),
+ 1, 4, 100, 3, 0 },
+ },
+ 100, /* probe interval */
+ 100, /* rssi reduce interval */
+ 0, /* Phy rates allowed initially */
+};
+
+static void ar5416_attach_ratetables(struct ath_rate_softc *sc)
+{
+ /*
+ * Attach rate tables.
+ */
+ sc->hw_rate_table[ATH9K_MODE_11B] = &ar5416_11b_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11G] = &ar5416_11g_ratetable;
+
+ sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] =
+ &ar5416_11na_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] =
+ &ar5416_11na_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] =
+ &ar5416_11ng_ratetable;
+ sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] =
+ &ar5416_11ng_ratetable;
+}
+
+static void ar5416_setquarter_ratetable(struct ath_rate_softc *sc)
+{
+ sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Quarter;
+ return;
+}
+
+static void ar5416_sethalf_ratetable(struct ath_rate_softc *sc)
+{
+ sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Half;
+ return;
+}
+
+static void ar5416_setfull_ratetable(struct ath_rate_softc *sc)
+{
+ sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable;
+ return;
+}
+
+/*
+ * Return the median of three numbers
+ */
+static inline int8_t median(int8_t a, int8_t b, int8_t c)
+{
+ if (a >= b) {
+ if (b >= c)
+ return b;
+ else if (a > c)
+ return c;
+ else
+ return a;
+ } else {
+ if (a >= c)
+ return a;
+ else if (b >= c)
+ return c;
+ else
+ return b;
+ }
+}
+
+static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table,
+ struct ath_tx_ratectrl *rate_ctrl)
+{
+ u8 i, j, idx, idx_next;
+
+ for (i = rate_ctrl->max_valid_rate - 1; i > 0; i--) {
+ for (j = 0; j <= i-1; j++) {
+ idx = rate_ctrl->valid_rate_index[j];
+ idx_next = rate_ctrl->valid_rate_index[j+1];
+
+ if (rate_table->info[idx].ratekbps >
+ rate_table->info[idx_next].ratekbps) {
+ rate_ctrl->valid_rate_index[j] = idx_next;
+ rate_ctrl->valid_rate_index[j+1] = idx;
+ }
+ }
+ }
+}
+
+/* Access functions for valid_txrate_mask */
+
+static void ath_rc_init_valid_txmask(struct ath_tx_ratectrl *rate_ctrl)
+{
+ u8 i;
+
+ for (i = 0; i < rate_ctrl->rate_table_size; i++)
+ rate_ctrl->valid_rate_index[i] = FALSE;
+}
+
+static inline void ath_rc_set_valid_txmask(struct ath_tx_ratectrl *rate_ctrl,
+ u8 index, int valid_tx_rate)
+{
+ ASSERT(index <= rate_ctrl->rate_table_size);
+ rate_ctrl->valid_rate_index[index] = valid_tx_rate ? TRUE : FALSE;
+}
+
+static inline int ath_rc_isvalid_txmask(struct ath_tx_ratectrl *rate_ctrl,
+ u8 index)
+{
+ ASSERT(index <= rate_ctrl->rate_table_size);
+ return rate_ctrl->valid_rate_index[index];
+}
+
+/* Iterators for valid_txrate_mask */
+static inline int
+ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
+ struct ath_tx_ratectrl *rate_ctrl,
+ u8 cur_valid_txrate,
+ u8 *next_idx)
+{
+ u8 i;
+
+ for (i = 0; i < rate_ctrl->max_valid_rate - 1; i++) {
+ if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) {
+ *next_idx = rate_ctrl->valid_rate_index[i+1];
+ return TRUE;
+ }
+ }
+
+ /* No more valid rates */
+ *next_idx = 0;
+ return FALSE;
+}
+
+/* Return true only for single stream */
+
+static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
+{
+ if (WLAN_RC_PHY_HT(phy) & !(capflag & WLAN_RC_HT_FLAG))
+ return FALSE;
+ if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG))
+ return FALSE;
+ if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG))
+ return FALSE;
+ if (!ignore_cw && WLAN_RC_PHY_HT(phy))
+ if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG))
+ return FALSE;
+ if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG))
+ return FALSE;
+ return TRUE;
+}
+
+static inline int
+ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table,
+ struct ath_tx_ratectrl *rate_ctrl,
+ u8 cur_valid_txrate, u8 *next_idx)
+{
+ int8_t i;
+
+ for (i = 1; i < rate_ctrl->max_valid_rate ; i++) {
+ if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) {
+ *next_idx = rate_ctrl->valid_rate_index[i-1];
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Initialize the Valid Rate Index from valid entries in Rate Table
+ */
+static u8
+ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv,
+ const struct ath_rate_table *rate_table,
+ u32 capflag)
+{
+ struct ath_tx_ratectrl *rate_ctrl;
+ u8 i, hi = 0;
+ u32 valid;
+
+ rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
+ for (i = 0; i < rate_table->rate_cnt; i++) {
+ valid = (ath_rc_priv->single_stream ?
+ rate_table->info[i].valid_single_stream :
+ rate_table->info[i].valid);
+ if (valid == TRUE) {
+ u32 phy = rate_table->info[i].phy;
+ u8 valid_rate_count = 0;
+
+ if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+ continue;
+
+ valid_rate_count = rate_ctrl->valid_phy_ratecnt[phy];
+
+ rate_ctrl->valid_phy_rateidx[phy][valid_rate_count] = i;
+ rate_ctrl->valid_phy_ratecnt[phy] += 1;
+ ath_rc_set_valid_txmask(rate_ctrl, i, TRUE);
+ hi = A_MAX(hi, i);
+ }
+ }
+ return hi;
+}
+
+/*
+ * Initialize the Valid Rate Index from Rate Set
+ */
+static u8
+ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv,
+ const struct ath_rate_table *rate_table,
+ struct ath_rateset *rateset,
+ u32 capflag)
+{
+ /* XXX: Clean me up and make identation friendly */
+ u8 i, j, hi = 0;
+ struct ath_tx_ratectrl *rate_ctrl =
+ (struct ath_tx_ratectrl *)(ath_rc_priv);
+
+ /* Use intersection of working rates and valid rates */
+ for (i = 0; i < rateset->rs_nrates; i++) {
+ for (j = 0; j < rate_table->rate_cnt; j++) {
+ u32 phy = rate_table->info[j].phy;
+ u32 valid = (ath_rc_priv->single_stream ?
+ rate_table->info[j].valid_single_stream :
+ rate_table->info[j].valid);
+
+ /* We allow a rate only if its valid and the
+ * capflag matches one of the validity
+ * (TRUE/TRUE_20/TRUE_40) flags */
+
+ /* XXX: catch the negative of this branch
+ * first and then continue */
+ if (((rateset->rs_rates[i] & 0x7F) ==
+ (rate_table->info[j].dot11rate & 0x7F)) &&
+ ((valid & WLAN_RC_CAP_MODE(capflag)) ==
+ WLAN_RC_CAP_MODE(capflag)) &&
+ !WLAN_RC_PHY_HT(phy)) {
+
+ u8 valid_rate_count = 0;
+
+ if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+ continue;
+
+ valid_rate_count =
+ rate_ctrl->valid_phy_ratecnt[phy];
+
+ rate_ctrl->valid_phy_rateidx[phy]
+ [valid_rate_count] = j;
+ rate_ctrl->valid_phy_ratecnt[phy] += 1;
+ ath_rc_set_valid_txmask(rate_ctrl, j, TRUE);
+ hi = A_MAX(hi, j);
+ }
+ }
+ }
+ return hi;
+}
+
+static u8
+ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv,
+ const struct ath_rate_table *rate_table,
+ u8 *mcs_set, u32 capflag)
+{
+ u8 i, j, hi = 0;
+ struct ath_tx_ratectrl *rate_ctrl =
+ (struct ath_tx_ratectrl *)(ath_rc_priv);
+
+ /* Use intersection of working rates and valid rates */
+ for (i = 0; i < ((struct ath_rateset *)mcs_set)->rs_nrates; i++) {
+ for (j = 0; j < rate_table->rate_cnt; j++) {
+ u32 phy = rate_table->info[j].phy;
+ u32 valid = (ath_rc_priv->single_stream ?
+ rate_table->info[j].valid_single_stream :
+ rate_table->info[j].valid);
+
+ if (((((struct ath_rateset *)
+ mcs_set)->rs_rates[i] & 0x7F) !=
+ (rate_table->info[j].dot11rate & 0x7F)) ||
+ !WLAN_RC_PHY_HT(phy) ||
+ !WLAN_RC_PHY_HT_VALID(valid, capflag))
+ continue;
+
+ if (!ath_rc_valid_phyrate(phy, capflag, FALSE))
+ continue;
+
+ rate_ctrl->valid_phy_rateidx[phy]
+ [rate_ctrl->valid_phy_ratecnt[phy]] = j;
+ rate_ctrl->valid_phy_ratecnt[phy] += 1;
+ ath_rc_set_valid_txmask(rate_ctrl, j, TRUE);
+ hi = A_MAX(hi, j);
+ }
+ }
+ return hi;
+}
+
+/*
+ * Attach to a device instance. Setup the public definition
+ * of how much per-node space we need and setup the private
+ * phy tables that have rate control parameters.
+ */
+struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah)
+{
+ struct ath_rate_softc *asc;
+
+ /* we are only in user context so we can sleep for memory */
+ asc = kzalloc(sizeof(struct ath_rate_softc), GFP_KERNEL);
+ if (asc == NULL)
+ return NULL;
+
+ ar5416_attach_ratetables(asc);
+
+ /* Save Maximum TX Trigger Level (used for 11n) */
+ tx_triglevel_max = ah->ah_caps.tx_triglevel_max;
+ /* return alias for ath_rate_softc * */
+ return asc;
+}
+
+static struct ath_rate_node *ath_rate_node_alloc(struct ath_vap *avp,
+ struct ath_rate_softc *rsc,
+ gfp_t gfp)
+{
+ struct ath_rate_node *anode;
+
+ anode = kzalloc(sizeof(struct ath_rate_node), gfp);
+ if (anode == NULL)
+ return NULL;
+
+ anode->avp = avp;
+ anode->asc = rsc;
+ avp->rc_node = anode;
+
+ return anode;
+}
+
+static void ath_rate_node_free(struct ath_rate_node *anode)
+{
+ if (anode != NULL)
+ kfree(anode);
+}
+
+void ath_rate_detach(struct ath_rate_softc *asc)
+{
+ if (asc != NULL)
+ kfree(asc);
+}
+
+u8 ath_rate_findrateix(struct ath_softc *sc,
+ u8 dot11rate)
+{
+ const struct ath_rate_table *ratetable;
+ struct ath_rate_softc *rsc = sc->sc_rc;
+ int i;
+
+ ratetable = rsc->hw_rate_table[sc->sc_curmode];
+
+ if (WARN_ON(!ratetable))
+ return 0;
+
+ for (i = 0; i < ratetable->rate_cnt; i++) {
+ if ((ratetable->info[i].dot11rate & 0x7f) == (dot11rate & 0x7f))
+ return i;
+ }
+
+ return 0;
+}
+
+/*
+ * Update rate-control state on a device state change. When
+ * operating as a station this includes associate/reassociate
+ * with an AP. Otherwise this gets called, for example, when
+ * the we transition to run state when operating as an AP.
+ */
+void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp)
+{
+ struct ath_rate_softc *asc = sc->sc_rc;
+
+ /* For half and quarter rate channles use different
+ * rate tables
+ */
+ if (sc->sc_curchan.channelFlags & CHANNEL_HALF)
+ ar5416_sethalf_ratetable(asc);
+ else if (sc->sc_curchan.channelFlags & CHANNEL_QUARTER)
+ ar5416_setquarter_ratetable(asc);
+ else /* full rate */
+ ar5416_setfull_ratetable(asc);
+
+ if (avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) {
+ asc->fixedrix =
+ sc->sc_rixmap[avp->av_config.av_fixed_rateset & 0xff];
+ /* NB: check the fixed rate exists */
+ if (asc->fixedrix == 0xff)
+ asc->fixedrix = IEEE80211_FIXED_RATE_NONE;
+ } else {
+ asc->fixedrix = IEEE80211_FIXED_RATE_NONE;
+ }
+}
+
+static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
+ struct ath_rate_node *ath_rc_priv,
+ const struct ath_rate_table *rate_table,
+ int probe_allowed, int *is_probing,
+ int is_retry)
+{
+ u32 dt, best_thruput, this_thruput, now_msec;
+ u8 rate, next_rate, best_rate, maxindex, minindex;
+ int8_t rssi_last, rssi_reduce = 0, index = 0;
+ struct ath_tx_ratectrl *rate_ctrl = NULL;
+
+ rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv ?
+ (ath_rc_priv) : NULL);
+
+ *is_probing = FALSE;
+
+ rssi_last = median(rate_ctrl->rssi_last,
+ rate_ctrl->rssi_last_prev,
+ rate_ctrl->rssi_last_prev2);
+
+ /*
+ * Age (reduce) last ack rssi based on how old it is.
+ * The bizarre numbers are so the delta is 160msec,
+ * meaning we divide by 16.
+ * 0msec <= dt <= 25msec: don't derate
+ * 25msec <= dt <= 185msec: derate linearly from 0 to 10dB
+ * 185msec <= dt: derate by 10dB
+ */
+
+ now_msec = jiffies_to_msecs(jiffies);
+ dt = now_msec - rate_ctrl->rssi_time;
+
+ if (dt >= 185)
+ rssi_reduce = 10;
+ else if (dt >= 25)
+ rssi_reduce = (u8)((dt - 25) >> 4);
+
+ /* Now reduce rssi_last by rssi_reduce */
+ if (rssi_last < rssi_reduce)
+ rssi_last = 0;
+ else
+ rssi_last -= rssi_reduce;
+
+ /*
+ * Now look up the rate in the rssi table and return it.
+ * If no rates match then we return 0 (lowest rate)
+ */
+
+ best_thruput = 0;
+ maxindex = rate_ctrl->max_valid_rate-1;
+
+ minindex = 0;
+ best_rate = minindex;
+
+ /*
+ * Try the higher rate first. It will reduce memory moving time
+ * if we have very good channel characteristics.
+ */
+ for (index = maxindex; index >= minindex ; index--) {
+ u8 per_thres;
+
+ rate = rate_ctrl->valid_rate_index[index];
+ if (rate > rate_ctrl->rate_max_phy)
+ continue;
+
+ /*
+ * For TCP the average collision rate is around 11%,
+ * so we ignore PERs less than this. This is to
+ * prevent the rate we are currently using (whose
+ * PER might be in the 10-15 range because of TCP
+ * collisions) looking worse than the next lower
+ * rate whose PER has decayed close to 0. If we
+ * used to next lower rate, its PER would grow to
+ * 10-15 and we would be worse off then staying
+ * at the current rate.
+ */
+ per_thres = rate_ctrl->state[rate].per;
+ if (per_thres < 12)
+ per_thres = 12;
+
+ this_thruput = rate_table->info[rate].user_ratekbps *
+ (100 - per_thres);
+
+ if (best_thruput <= this_thruput) {
+ best_thruput = this_thruput;
+ best_rate = rate;
+ }
+ }
+
+ rate = best_rate;
+
+ /* if we are retrying for more than half the number
+ * of max retries, use the min rate for the next retry
+ */
+ if (is_retry)
+ rate = rate_ctrl->valid_rate_index[minindex];
+
+ rate_ctrl->rssi_last_lookup = rssi_last;
+
+ /*
+ * Must check the actual rate (ratekbps) to account for
+ * non-monoticity of 11g's rate table
+ */
+
+ if (rate >= rate_ctrl->rate_max_phy && probe_allowed) {
+ rate = rate_ctrl->rate_max_phy;
+
+ /* Probe the next allowed phy state */
+ /* FIXME:XXXX Check to make sure ratMax is checked properly */
+ if (ath_rc_get_nextvalid_txrate(rate_table,
+ rate_ctrl, rate, &next_rate) &&
+ (now_msec - rate_ctrl->probe_time >
+ rate_table->probe_interval) &&
+ (rate_ctrl->hw_maxretry_pktcnt >= 1)) {
+ rate = next_rate;
+ rate_ctrl->probe_rate = rate;
+ rate_ctrl->probe_time = now_msec;
+ rate_ctrl->hw_maxretry_pktcnt = 0;
+ *is_probing = TRUE;
+ }
+ }
+
+ /*
+ * Make sure rate is not higher than the allowed maximum.
+ * We should also enforce the min, but I suspect the min is
+ * normally 1 rather than 0 because of the rate 9 vs 6 issue
+ * in the old code.
+ */
+ if (rate > (rate_ctrl->rate_table_size - 1))
+ rate = rate_ctrl->rate_table_size - 1;
+
+ ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) ||
+ (rate_table->info[rate].valid_single_stream &&
+ ath_rc_priv->single_stream));
+
+ return rate;
+}
+
+static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table ,
+ struct ath_rc_series *series,
+ u8 tries,
+ u8 rix,
+ int rtsctsenable)
+{
+ series->tries = tries;
+ series->flags = (rtsctsenable ? ATH_RC_RTSCTS_FLAG : 0) |
+ (WLAN_RC_PHY_DS(rate_table->info[rix].phy) ?
+ ATH_RC_DS_FLAG : 0) |
+ (WLAN_RC_PHY_40(rate_table->info[rix].phy) ?
+ ATH_RC_CW40_FLAG : 0) |
+ (WLAN_RC_PHY_SGI(rate_table->info[rix].phy) ?
+ ATH_RC_SGI_FLAG : 0);
+
+ series->rix = rate_table->info[rix].base_index;
+ series->max_4ms_framelen = rate_table->info[rix].max_4ms_framelen;
+}
+
+static u8 ath_rc_rate_getidx(struct ath_softc *sc,
+ struct ath_rate_node *ath_rc_priv,
+ const struct ath_rate_table *rate_table,
+ u8 rix, u16 stepdown,
+ u16 min_rate)
+{
+ u32 j;
+ u8 nextindex;
+ struct ath_tx_ratectrl *rate_ctrl =
+ (struct ath_tx_ratectrl *)(ath_rc_priv);
+
+ if (min_rate) {
+ for (j = RATE_TABLE_SIZE; j > 0; j--) {
+ if (ath_rc_get_nextlowervalid_txrate(rate_table,
+ rate_ctrl, rix, &nextindex))
+ rix = nextindex;
+ else
+ break;
+ }
+ } else {
+ for (j = stepdown; j > 0; j--) {
+ if (ath_rc_get_nextlowervalid_txrate(rate_table,
+ rate_ctrl, rix, &nextindex))
+ rix = nextindex;
+ else
+ break;
+ }
+ }
+ return rix;
+}
+
+static void ath_rc_ratefind(struct ath_softc *sc,
+ struct ath_rate_node *ath_rc_priv,
+ int num_tries, int num_rates, unsigned int rcflag,
+ struct ath_rc_series series[], int *is_probe,
+ int is_retry)
+{
+ u8 try_per_rate = 0, i = 0, rix, nrix;
+ struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
+ struct ath_rate_table *rate_table;
+
+ rate_table =
+ (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
+ rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table,
+ (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0,
+ is_probe, is_retry);
+ nrix = rix;
+
+ if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*is_probe)) {
+ /* set one try for probe rates. For the
+ * probes don't enable rts */
+ ath_rc_rate_set_series(rate_table,
+ &series[i++], 1, nrix, FALSE);
+
+ try_per_rate = (num_tries/num_rates);
+ /* Get the next tried/allowed rate. No RTS for the next series
+ * after the probe rate
+ */
+ nrix = ath_rc_rate_getidx(sc,
+ ath_rc_priv, rate_table, nrix, 1, FALSE);
+ ath_rc_rate_set_series(rate_table,
+ &series[i++], try_per_rate, nrix, 0);
+ } else {
+ try_per_rate = (num_tries/num_rates);
+ /* Set the choosen rate. No RTS for first series entry. */
+ ath_rc_rate_set_series(rate_table,
+ &series[i++], try_per_rate, nrix, FALSE);
+ }
+
+ /* Fill in the other rates for multirate retry */
+ for ( ; i < num_rates; i++) {
+ u8 try_num;
+ u8 min_rate;
+
+ try_num = ((i + 1) == num_rates) ?
+ num_tries - (try_per_rate * i) : try_per_rate ;
+ min_rate = (((i + 1) == num_rates) &&
+ (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0;
+
+ nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
+ rate_table, nrix, 1, min_rate);
+ /* All other rates in the series have RTS enabled */
+ ath_rc_rate_set_series(rate_table,
+ &series[i], try_num, nrix, TRUE);
+ }
+
+ /*
+ * NB:Change rate series to enable aggregation when operating
+ * at lower MCS rates. When first rate in series is MCS2
+ * in HT40 @ 2.4GHz, series should look like:
+ *
+ * {MCS2, MCS1, MCS0, MCS0}.
+ *
+ * When first rate in series is MCS3 in HT20 @ 2.4GHz, series should
+ * look like:
+ *
+ * {MCS3, MCS2, MCS1, MCS1}
+ *
+ * So, set fourth rate in series to be same as third one for
+ * above conditions.
+ */
+ if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) ||
+ (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) ||
+ (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) {
+ u8 dot11rate = rate_table->info[rix].dot11rate;
+ u8 phy = rate_table->info[rix].phy;
+ if (i == 4 &&
+ ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) ||
+ (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) {
+ series[3].rix = series[2].rix;
+ series[3].flags = series[2].flags;
+ series[3].max_4ms_framelen = series[2].max_4ms_framelen;
+ }
+ }
+}
+
+/*
+ * Return the Tx rate series.
+ */
+void ath_rate_findrate(struct ath_softc *sc,
+ struct ath_rate_node *ath_rc_priv,
+ int num_tries,
+ int num_rates,
+ unsigned int rcflag,
+ struct ath_rc_series series[],
+ int *is_probe,
+ int is_retry)
+{
+ struct ath_vap *avp = ath_rc_priv->avp;
+
+ DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
+ if (!num_rates || !num_tries)
+ return;
+
+ if (avp->av_config.av_fixed_rateset == IEEE80211_FIXED_RATE_NONE) {
+ ath_rc_ratefind(sc, ath_rc_priv, num_tries, num_rates,
+ rcflag, series, is_probe, is_retry);
+ } else {
+ /* Fixed rate */
+ int idx;
+ u8 flags;
+ u32 rix;
+ struct ath_rate_softc *asc = ath_rc_priv->asc;
+ struct ath_rate_table *rate_table;
+
+ rate_table = (struct ath_rate_table *)
+ asc->hw_rate_table[sc->sc_curmode];
+
+ for (idx = 0; idx < 4; idx++) {
+ unsigned int mcs;
+ u8 series_rix = 0;
+
+ series[idx].tries =
+ IEEE80211_RATE_IDX_ENTRY(
+ avp->av_config.av_fixed_retryset, idx);
+
+ mcs = IEEE80211_RATE_IDX_ENTRY(
+ avp->av_config.av_fixed_rateset, idx);
+
+ if (idx == 3 && (mcs & 0xf0) == 0x70)
+ mcs = (mcs & ~0xf0)|0x80;
+
+ if (!(mcs & 0x80))
+ flags = 0;
+ else
+ flags = ((ath_rc_priv->ht_cap &
+ WLAN_RC_DS_FLAG) ?
+ ATH_RC_DS_FLAG : 0) |
+ ((ath_rc_priv->ht_cap &
+ WLAN_RC_40_FLAG) ?
+ ATH_RC_CW40_FLAG : 0) |
+ ((ath_rc_priv->ht_cap &
+ WLAN_RC_SGI_FLAG) ?
+ ((ath_rc_priv->ht_cap &
+ WLAN_RC_40_FLAG) ?
+ ATH_RC_SGI_FLAG : 0) : 0);
+
+ series[idx].rix = sc->sc_rixmap[mcs];
+ series_rix = series[idx].rix;
+
+ /* XXX: Give me some cleanup love */
+ if ((flags & ATH_RC_CW40_FLAG) &&
+ (flags & ATH_RC_SGI_FLAG))
+ rix = rate_table->info[series_rix].ht_index;
+ else if (flags & ATH_RC_SGI_FLAG)
+ rix = rate_table->info[series_rix].sgi_index;
+ else if (flags & ATH_RC_CW40_FLAG)
+ rix = rate_table->info[series_rix].cw40index;
+ else
+ rix = rate_table->info[series_rix].base_index;
+ series[idx].max_4ms_framelen =
+ rate_table->info[rix].max_4ms_framelen;
+ series[idx].flags = flags;
+ }
+ }
+}
+
+static void ath_rc_update_ht(struct ath_softc *sc,
+ struct ath_rate_node *ath_rc_priv,
+ struct ath_tx_info_priv *info_priv,
+ int tx_rate, int xretries, int retries)
+{
+ struct ath_tx_ratectrl *rate_ctrl;
+ u32 now_msec = jiffies_to_msecs(jiffies);
+ int state_change = FALSE, rate, count;
+ u8 last_per;
+ struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
+ struct ath_rate_table *rate_table =
+ (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode];
+
+ static u32 nretry_to_per_lookup[10] = {
+ 100 * 0 / 1,
+ 100 * 1 / 4,
+ 100 * 1 / 2,
+ 100 * 3 / 4,
+ 100 * 4 / 5,
+ 100 * 5 / 6,
+ 100 * 6 / 7,
+ 100 * 7 / 8,
+ 100 * 8 / 9,
+ 100 * 9 / 10
+ };
+
+ if (!ath_rc_priv)
+ return;
+
+ rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
+
+ ASSERT(tx_rate >= 0);
+ if (tx_rate < 0)
+ return;
+
+ /* To compensate for some imbalance between ctrl and ext. channel */
+
+ if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
+ info_priv->tx.ts_rssi =
+ info_priv->tx.ts_rssi < 3 ? 0 :
+ info_priv->tx.ts_rssi - 3;
+
+ last_per = rate_ctrl->state[tx_rate].per;
+
+ if (xretries) {
+ /* Update the PER. */
+ if (xretries == 1) {
+ rate_ctrl->state[tx_rate].per += 30;
+ if (rate_ctrl->state[tx_rate].per > 100)
+ rate_ctrl->state[tx_rate].per = 100;
+ } else {
+ /* xretries == 2 */
+ count = sizeof(nretry_to_per_lookup) /
+ sizeof(nretry_to_per_lookup[0]);
+ if (retries >= count)
+ retries = count - 1;
+ /* new_PER = 7/8*old_PER + 1/8*(currentPER) */
+ rate_ctrl->state[tx_rate].per =
+ (u8)(rate_ctrl->state[tx_rate].per -
+ (rate_ctrl->state[tx_rate].per >> 3) +
+ ((100) >> 3));
+ }
+
+ /* xretries == 1 or 2 */
+
+ if (rate_ctrl->probe_rate == tx_rate)
+ rate_ctrl->probe_rate = 0;
+
+ } else { /* xretries == 0 */
+ /* Update the PER. */
+ /* Make sure it doesn't index out of array's bounds. */
+ count = sizeof(nretry_to_per_lookup) /
+ sizeof(nretry_to_per_lookup[0]);
+ if (retries >= count)
+ retries = count - 1;
+ if (info_priv->n_bad_frames) {
+ /* new_PER = 7/8*old_PER + 1/8*(currentPER) */
+ /*
+ * Assuming that n_frames is not 0. The current PER
+ * from the retries is 100 * retries / (retries+1),
+ * since the first retries attempts failed, and the
+ * next one worked. For the one that worked,
+ * n_bad_frames subframes out of n_frames wored,
+ * so the PER for that part is
+ * 100 * n_bad_frames / n_frames, and it contributes
+ * 100 * n_bad_frames / (n_frames * (retries+1)) to
+ * the above PER. The expression below is a
+ * simplified version of the sum of these two terms.
+ */
+ if (info_priv->n_frames > 0)
+ rate_ctrl->state[tx_rate].per
+ = (u8)
+ (rate_ctrl->state[tx_rate].per -
+ (rate_ctrl->state[tx_rate].per >> 3) +
+ ((100*(retries*info_priv->n_frames +
+ info_priv->n_bad_frames) /
+ (info_priv->n_frames *
+ (retries+1))) >> 3));
+ } else {
+ /* new_PER = 7/8*old_PER + 1/8*(currentPER) */
+
+ rate_ctrl->state[tx_rate].per = (u8)
+ (rate_ctrl->state[tx_rate].per -
+ (rate_ctrl->state[tx_rate].per >> 3) +
+ (nretry_to_per_lookup[retries] >> 3));
+ }
+
+ rate_ctrl->rssi_last_prev2 = rate_ctrl->rssi_last_prev;
+ rate_ctrl->rssi_last_prev = rate_ctrl->rssi_last;
+ rate_ctrl->rssi_last = info_priv->tx.ts_rssi;
+ rate_ctrl->rssi_time = now_msec;
+
+ /*
+ * If we got at most one retry then increase the max rate if
+ * this was a probe. Otherwise, ignore the probe.
+ */
+
+ if (rate_ctrl->probe_rate && rate_ctrl->probe_rate == tx_rate) {
+ if (retries > 0 || 2 * info_priv->n_bad_frames >
+ info_priv->n_frames) {
+ /*
+ * Since we probed with just a single attempt,
+ * any retries means the probe failed. Also,
+ * if the attempt worked, but more than half
+ * the subframes were bad then also consider
+ * the probe a failure.
+ */
+ rate_ctrl->probe_rate = 0;
+ } else {
+ u8 probe_rate = 0;
+
+ rate_ctrl->rate_max_phy = rate_ctrl->probe_rate;
+ probe_rate = rate_ctrl->probe_rate;
+
+ if (rate_ctrl->state[probe_rate].per > 30)
+ rate_ctrl->state[probe_rate].per = 20;
+
+ rate_ctrl->probe_rate = 0;
+
+ /*
+ * Since this probe succeeded, we allow the next
+ * probe twice as soon. This allows the maxRate
+ * to move up faster if the probes are
+ * succesful.
+ */
+ rate_ctrl->probe_time = now_msec -
+ rate_table->probe_interval / 2;
+ }
+ }
+
+ if (retries > 0) {
+ /*
+ * Don't update anything. We don't know if
+ * this was because of collisions or poor signal.
+ *
+ * Later: if rssi_ack is close to
+ * rate_ctrl->state[txRate].rssi_thres and we see lots
+ * of retries, then we could increase
+ * rate_ctrl->state[txRate].rssi_thres.
+ */
+ rate_ctrl->hw_maxretry_pktcnt = 0;
+ } else {
+ /*
+ * It worked with no retries. First ignore bogus (small)
+ * rssi_ack values.
+ */
+ if (tx_rate == rate_ctrl->rate_max_phy &&
+ rate_ctrl->hw_maxretry_pktcnt < 255) {
+ rate_ctrl->hw_maxretry_pktcnt++;
+ }
+
+ if (info_priv->tx.ts_rssi >=
+ rate_table->info[tx_rate].rssi_ack_validmin) {
+ /* Average the rssi */
+ if (tx_rate != rate_ctrl->rssi_sum_rate) {
+ rate_ctrl->rssi_sum_rate = tx_rate;
+ rate_ctrl->rssi_sum =
+ rate_ctrl->rssi_sum_cnt = 0;
+ }
+
+ rate_ctrl->rssi_sum += info_priv->tx.ts_rssi;
+ rate_ctrl->rssi_sum_cnt++;
+
+ if (rate_ctrl->rssi_sum_cnt > 4) {
+ int32_t rssi_ackAvg =
+ (rate_ctrl->rssi_sum + 2) / 4;
+ int8_t rssi_thres =
+ rate_ctrl->state[tx_rate].
+ rssi_thres;
+ int8_t rssi_ack_vmin =
+ rate_table->info[tx_rate].
+ rssi_ack_validmin;
+
+ rate_ctrl->rssi_sum =
+ rate_ctrl->rssi_sum_cnt = 0;
+
+ /* Now reduce the current
+ * rssi threshold. */
+ if ((rssi_ackAvg < rssi_thres + 2) &&
+ (rssi_thres > rssi_ack_vmin)) {
+ rate_ctrl->state[tx_rate].
+ rssi_thres--;
+ }
+
+ state_change = TRUE;
+ }
+ }
+ }
+ }
+
+ /* For all cases */
+
+ /*
+ * If this rate looks bad (high PER) then stop using it for
+ * a while (except if we are probing).
+ */
+ if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 &&
+ rate_table->info[tx_rate].ratekbps <=
+ rate_table->info[rate_ctrl->rate_max_phy].ratekbps) {
+ ath_rc_get_nextlowervalid_txrate(rate_table, rate_ctrl,
+ (u8) tx_rate, &rate_ctrl->rate_max_phy);
+
+ /* Don't probe for a little while. */
+ rate_ctrl->probe_time = now_msec;
+ }
+
+ if (state_change) {
+ /*
+ * Make sure the rates above this have higher rssi thresholds.
+ * (Note: Monotonicity is kept within the OFDM rates and
+ * within the CCK rates. However, no adjustment is
+ * made to keep the rssi thresholds monotonically
+ * increasing between the CCK and OFDM rates.)
+ */
+ for (rate = tx_rate; rate <
+ rate_ctrl->rate_table_size - 1; rate++) {
+ if (rate_table->info[rate+1].phy !=
+ rate_table->info[tx_rate].phy)
+ break;
+
+ if (rate_ctrl->state[rate].rssi_thres +
+ rate_table->info[rate].rssi_ack_deltamin >
+ rate_ctrl->state[rate+1].rssi_thres) {
+ rate_ctrl->state[rate+1].rssi_thres =
+ rate_ctrl->state[rate].
+ rssi_thres +
+ rate_table->info[rate].
+ rssi_ack_deltamin;
+ }
+ }
+
+ /* Make sure the rates below this have lower rssi thresholds. */
+ for (rate = tx_rate - 1; rate >= 0; rate--) {
+ if (rate_table->info[rate].phy !=
+ rate_table->info[tx_rate].phy)
+ break;
+
+ if (rate_ctrl->state[rate].rssi_thres +
+ rate_table->info[rate].rssi_ack_deltamin >
+ rate_ctrl->state[rate+1].rssi_thres) {
+ if (rate_ctrl->state[rate+1].rssi_thres <
+ rate_table->info[rate].
+ rssi_ack_deltamin)
+ rate_ctrl->state[rate].rssi_thres = 0;
+ else {
+ rate_ctrl->state[rate].rssi_thres =
+ rate_ctrl->state[rate+1].
+ rssi_thres -
+ rate_table->info[rate].
+ rssi_ack_deltamin;
+ }
+
+ if (rate_ctrl->state[rate].rssi_thres <
+ rate_table->info[rate].
+ rssi_ack_validmin) {
+ rate_ctrl->state[rate].rssi_thres =
+ rate_table->info[rate].
+ rssi_ack_validmin;
+ }
+ }
+ }
+ }
+
+ /* Make sure the rates below this have lower PER */
+ /* Monotonicity is kept only for rates below the current rate. */
+ if (rate_ctrl->state[tx_rate].per < last_per) {
+ for (rate = tx_rate - 1; rate >= 0; rate--) {
+ if (rate_table->info[rate].phy !=
+ rate_table->info[tx_rate].phy)
+ break;
+
+ if (rate_ctrl->state[rate].per >
+ rate_ctrl->state[rate+1].per) {
+ rate_ctrl->state[rate].per =
+ rate_ctrl->state[rate+1].per;
+ }
+ }
+ }
+
+ /* Maintain monotonicity for rates above the current rate */
+ for (rate = tx_rate; rate < rate_ctrl->rate_table_size - 1; rate++) {
+ if (rate_ctrl->state[rate+1].per < rate_ctrl->state[rate].per)
+ rate_ctrl->state[rate+1].per =
+ rate_ctrl->state[rate].per;
+ }
+
+ /* Every so often, we reduce the thresholds and
+ * PER (different for CCK and OFDM). */
+ if (now_msec - rate_ctrl->rssi_down_time >=
+ rate_table->rssi_reduce_interval) {
+
+ for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
+ if (rate_ctrl->state[rate].rssi_thres >
+ rate_table->info[rate].rssi_ack_validmin)
+ rate_ctrl->state[rate].rssi_thres -= 1;
+ }
+ rate_ctrl->rssi_down_time = now_msec;
+ }
+
+ /* Every so often, we reduce the thresholds
+ * and PER (different for CCK and OFDM). */
+ if (now_msec - rate_ctrl->per_down_time >=
+ rate_table->rssi_reduce_interval) {
+ for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) {
+ rate_ctrl->state[rate].per =
+ 7 * rate_ctrl->state[rate].per / 8;
+ }
+
+ rate_ctrl->per_down_time = now_msec;
+ }
+}
+
+/*
+ * This routine is called in rate control callback tx_status() to give
+ * the status of previous frames.
+ */
+static void ath_rc_update(struct ath_softc *sc,
+ struct ath_rate_node *ath_rc_priv,
+ struct ath_tx_info_priv *info_priv, int final_ts_idx,
+ int xretries, int long_retry)
+{
+ struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
+ struct ath_rate_table *rate_table;
+ struct ath_tx_ratectrl *rate_ctrl;
+ struct ath_rc_series rcs[4];
+ u8 flags;
+ u32 series = 0, rix;
+
+ memcpy(rcs, info_priv->rcs, 4 * sizeof(rcs[0]));
+ rate_table = (struct ath_rate_table *)
+ asc->hw_rate_table[sc->sc_curmode];
+ rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
+ ASSERT(rcs[0].tries != 0);
+
+ /*
+ * If the first rate is not the final index, there
+ * are intermediate rate failures to be processed.
+ */
+ if (final_ts_idx != 0) {
+ /* Process intermediate rates that failed.*/
+ for (series = 0; series < final_ts_idx ; series++) {
+ if (rcs[series].tries != 0) {
+ flags = rcs[series].flags;
+ /* If HT40 and we have switched mode from
+ * 40 to 20 => don't update */
+ if ((flags & ATH_RC_CW40_FLAG) &&
+ (rate_ctrl->rc_phy_mode !=
+ (flags & ATH_RC_CW40_FLAG)))
+ return;
+ if ((flags & ATH_RC_CW40_FLAG) &&
+ (flags & ATH_RC_SGI_FLAG))
+ rix = rate_table->info[
+ rcs[series].rix].ht_index;
+ else if (flags & ATH_RC_SGI_FLAG)
+ rix = rate_table->info[
+ rcs[series].rix].sgi_index;
+ else if (flags & ATH_RC_CW40_FLAG)
+ rix = rate_table->info[
+ rcs[series].rix].cw40index;
+ else
+ rix = rate_table->info[
+ rcs[series].rix].base_index;
+ ath_rc_update_ht(sc, ath_rc_priv,
+ info_priv, rix,
+ xretries ? 1 : 2,
+ rcs[series].tries);
+ }
+ }
+ } else {
+ /*
+ * Handle the special case of MIMO PS burst, where the second
+ * aggregate is sent out with only one rate and one try.
+ * Treating it as an excessive retry penalizes the rate
+ * inordinately.
+ */
+ if (rcs[0].tries == 1 && xretries == 1)
+ xretries = 2;
+ }
+
+ flags = rcs[series].flags;
+ /* If HT40 and we have switched mode from 40 to 20 => don't update */
+ if ((flags & ATH_RC_CW40_FLAG) &&
+ (rate_ctrl->rc_phy_mode != (flags & ATH_RC_CW40_FLAG)))
+ return;
+
+ if ((flags & ATH_RC_CW40_FLAG) && (flags & ATH_RC_SGI_FLAG))
+ rix = rate_table->info[rcs[series].rix].ht_index;
+ else if (flags & ATH_RC_SGI_FLAG)
+ rix = rate_table->info[rcs[series].rix].sgi_index;
+ else if (flags & ATH_RC_CW40_FLAG)
+ rix = rate_table->info[rcs[series].rix].cw40index;
+ else
+ rix = rate_table->info[rcs[series].rix].base_index;
+
+ ath_rc_update_ht(sc, ath_rc_priv, info_priv, rix,
+ xretries, long_retry);
+}
+
+
+/*
+ * Process a tx descriptor for a completed transmit (success or failure).
+ */
+static void ath_rate_tx_complete(struct ath_softc *sc,
+ struct ath_node *an,
+ struct ath_rate_node *rc_priv,
+ struct ath_tx_info_priv *info_priv)
+{
+ int final_ts_idx = info_priv->tx.ts_rateindex;
+ int tx_status = 0, is_underrun = 0;
+ struct ath_vap *avp;
+
+ avp = rc_priv->avp;
+ if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE)
+ || info_priv->tx.ts_status & ATH9K_TXERR_FILT)
+ return;
+
+ if (info_priv->tx.ts_rssi > 0) {
+ ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi,
+ info_priv->tx.ts_rssi);
+ }
+
+ /*
+ * If underrun error is seen assume it as an excessive retry only
+ * if prefetch trigger level have reached the max (0x3f for 5416)
+ * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
+ * times. This affects how ratectrl updates PER for the failed rate.
+ */
+ if (info_priv->tx.ts_flags &
+ (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) &&
+ ((sc->sc_ah->ah_txTrigLevel) >= tx_triglevel_max)) {
+ tx_status = 1;
+ is_underrun = 1;
+ }
+
+ if ((info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) ||
+ (info_priv->tx.ts_status & ATH9K_TXERR_FIFO))
+ tx_status = 1;
+
+ ath_rc_update(sc, rc_priv, info_priv, final_ts_idx, tx_status,
+ (is_underrun) ? ATH_11N_TXMAXTRY :
+ info_priv->tx.ts_longretry);
+}
+
+
+/*
+ * Update the SIB's rate control information
+ *
+ * This should be called when the supported rates change
+ * (e.g. SME operation, wireless mode change)
+ *
+ * It will determine which rates are valid for use.
+ */
+static void ath_rc_sib_update(struct ath_softc *sc,
+ struct ath_rate_node *ath_rc_priv,
+ u32 capflag, int keep_state,
+ struct ath_rateset *negotiated_rates,
+ struct ath_rateset *negotiated_htrates)
+{
+ struct ath_rate_table *rate_table = NULL;
+ struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc;
+ struct ath_rateset *rateset = negotiated_rates;
+ u8 *ht_mcs = (u8 *)negotiated_htrates;
+ struct ath_tx_ratectrl *rate_ctrl = (struct ath_tx_ratectrl *)
+ (ath_rc_priv);
+ u8 i, j, k, hi = 0, hthi = 0;
+
+ rate_table = (struct ath_rate_table *)
+ asc->hw_rate_table[sc->sc_curmode];
+
+ /* Initial rate table size. Will change depending
+ * on the working rate set */
+ rate_ctrl->rate_table_size = MAX_TX_RATE_TBL;
+
+ /* Initialize thresholds according to the global rate table */
+ for (i = 0 ; (i < rate_ctrl->rate_table_size) && (!keep_state); i++) {
+ rate_ctrl->state[i].rssi_thres =
+ rate_table->info[i].rssi_ack_validmin;
+ rate_ctrl->state[i].per = 0;
+ }
+
+ /* Determine the valid rates */
+ ath_rc_init_valid_txmask(rate_ctrl);
+
+ for (i = 0; i < WLAN_RC_PHY_MAX; i++) {
+ for (j = 0; j < MAX_TX_RATE_PHY; j++)
+ rate_ctrl->valid_phy_rateidx[i][j] = 0;
+ rate_ctrl->valid_phy_ratecnt[i] = 0;
+ }
+ rate_ctrl->rc_phy_mode = (capflag & WLAN_RC_40_FLAG);
+
+ /* Set stream capability */
+ ath_rc_priv->single_stream = (capflag & WLAN_RC_DS_FLAG) ? 0 : 1;
+
+ if (!rateset->rs_nrates) {
+ /* No working rate, just initialize valid rates */
+ hi = ath_rc_sib_init_validrates(ath_rc_priv, rate_table,
+ capflag);
+ } else {
+ /* Use intersection of working rates and valid rates */
+ hi = ath_rc_sib_setvalid_rates(ath_rc_priv, rate_table,
+ rateset, capflag);
+ if (capflag & WLAN_RC_HT_FLAG) {
+ hthi = ath_rc_sib_setvalid_htrates(ath_rc_priv,
+ rate_table,
+ ht_mcs,
+ capflag);
+ }
+ hi = A_MAX(hi, hthi);
+ }
+
+ rate_ctrl->rate_table_size = hi + 1;
+ rate_ctrl->rate_max_phy = 0;
+ ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL);
+
+ for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) {
+ for (j = 0; j < rate_ctrl->valid_phy_ratecnt[i]; j++) {
+ rate_ctrl->valid_rate_index[k++] =
+ rate_ctrl->valid_phy_rateidx[i][j];
+ }
+
+ if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, TRUE)
+ || !rate_ctrl->valid_phy_ratecnt[i])
+ continue;
+
+ rate_ctrl->rate_max_phy = rate_ctrl->valid_phy_rateidx[i][j-1];
+ }
+ ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL);
+ ASSERT(k <= MAX_TX_RATE_TBL);
+
+ rate_ctrl->max_valid_rate = k;
+ /*
+ * Some third party vendors don't send the supported rate series in
+ * order. So sorting to make sure its in order, otherwise our RateFind
+ * Algo will select wrong rates
+ */
+ ath_rc_sort_validrates(rate_table, rate_ctrl);
+ rate_ctrl->rate_max_phy = rate_ctrl->valid_rate_index[k-4];
+}
+
+/*
+ * Update rate-control state on station associate/reassociate.
+ */
+static int ath_rate_newassoc(struct ath_softc *sc,
+ struct ath_rate_node *ath_rc_priv,
+ unsigned int capflag,
+ struct ath_rateset *negotiated_rates,
+ struct ath_rateset *negotiated_htrates)
+{
+
+
+ ath_rc_priv->ht_cap =
+ ((capflag & ATH_RC_DS_FLAG) ? WLAN_RC_DS_FLAG : 0) |
+ ((capflag & ATH_RC_SGI_FLAG) ? WLAN_RC_SGI_FLAG : 0) |
+ ((capflag & ATH_RC_HT_FLAG) ? WLAN_RC_HT_FLAG : 0) |
+ ((capflag & ATH_RC_CW40_FLAG) ? WLAN_RC_40_FLAG : 0);
+
+ ath_rc_sib_update(sc, ath_rc_priv, ath_rc_priv->ht_cap, 0,
+ negotiated_rates, negotiated_htrates);
+
+ return 0;
+}
+
+/*
+ * This routine is called to initialize the rate control parameters
+ * in the SIB. It is called initially during system initialization
+ * or when a station is associated with the AP.
+ */
+static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv)
+{
+ struct ath_tx_ratectrl *rate_ctrl;
+
+ rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv);
+ rate_ctrl->rssi_down_time = jiffies_to_msecs(jiffies);
+}
+
+
+static void ath_setup_rates(struct ieee80211_local *local, struct sta_info *sta)
+
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_hw *hw = local_to_hw(local);
+ struct ath_softc *sc = hw->priv;
+ struct ath_rate_node *rc_priv = sta->rate_ctrl_priv;
+ int i, j = 0;
+
+ DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (sta->supp_rates[local->hw.conf.channel->band] & BIT(i)) {
+ rc_priv->neg_rates.rs_rates[j]
+ = (sband->bitrates[i].bitrate * 2) / 10;
+ j++;
+ }
+ }
+ rc_priv->neg_rates.rs_nrates = j;
+}
+
+void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv)
+{
+ struct ath_softc *sc = hw->priv;
+ u32 capflag = 0;
+
+ if (hw->conf.ht_conf.ht_supported) {
+ capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG;
+ if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040)
+ capflag |= ATH_RC_CW40_FLAG;
+ }
+
+ ath_rate_newassoc(sc, rc_priv, capflag,
+ &rc_priv->neg_rates,
+ &rc_priv->neg_ht_rates);
+
+}
+
+/* Rate Control callbacks */
+static void ath_tx_status(void *priv, struct net_device *dev,
+ struct sk_buff *skb)
+{
+ struct ath_softc *sc = priv;
+ struct ath_tx_info_priv *tx_info_priv;
+ struct ath_node *an;
+ struct sta_info *sta;
+ struct ieee80211_local *local;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr;
+ __le16 fc;
+
+ local = hw_to_local(sc->hw);
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+
+ spin_lock_bh(&sc->node_lock);
+ an = ath_node_find(sc, hdr->addr1);
+ spin_unlock_bh(&sc->node_lock);
+
+ sta = sta_info_get(local, hdr->addr1);
+ if (!an || !sta || !ieee80211_is_data(fc)) {
+ if (tx_info->driver_data[0] != NULL) {
+ kfree(tx_info->driver_data[0]);
+ tx_info->driver_data[0] = NULL;
+ }
+ return;
+ }
+ if (tx_info->driver_data[0] != NULL) {
+ ath_rate_tx_complete(sc, an, sta->rate_ctrl_priv, tx_info_priv);
+ kfree(tx_info->driver_data[0]);
+ tx_info->driver_data[0] = NULL;
+ }
+}
+
+static void ath_tx_aggr_resp(struct ath_softc *sc,
+ struct sta_info *sta,
+ struct ath_node *an,
+ u8 tidno)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_local *local;
+ struct ath_atx_tid *txtid;
+ struct ieee80211_supported_band *sband;
+ u16 buffersize = 0;
+ int state;
+ DECLARE_MAC_BUF(mac);
+
+ if (!sc->sc_txaggr)
+ return;
+
+ txtid = ATH_AN_2_TID(an, tidno);
+ if (!txtid->paused)
+ return;
+
+ local = hw_to_local(sc->hw);
+ sband = hw->wiphy->bands[hw->conf.channel->band];
+ buffersize = IEEE80211_MIN_AMPDU_BUF <<
+ sband->ht_info.ampdu_factor; /* FIXME */
+ state = sta->ampdu_mlme.tid_state_tx[tidno];
+
+ if (state & HT_ADDBA_RECEIVED_MSK) {
+ txtid->addba_exchangecomplete = 1;
+ txtid->addba_exchangeinprogress = 0;
+ txtid->baw_size = buffersize;
+
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: Resuming tid, buffersize: %d\n",
+ __func__,
+ buffersize);
+
+ ath_tx_resume_tid(sc, txtid);
+ }
+}
+
+static void ath_get_rate(void *priv, struct net_device *dev,
+ struct ieee80211_supported_band *sband,
+ struct sk_buff *skb,
+ struct rate_selection *sel)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+ struct ath_softc *sc = (struct ath_softc *)priv;
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_tx_info_priv *tx_info_priv;
+ struct ath_rate_node *ath_rc_priv;
+ struct ath_node *an;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ int is_probe, chk, ret;
+ s8 lowest_idx;
+ __le16 fc = hdr->frame_control;
+ u8 *qc, tid;
+ DECLARE_MAC_BUF(mac);
+
+ DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
+
+ /* allocate driver private area of tx_info */
+ tx_info->driver_data[0] = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
+ ASSERT(tx_info->driver_data[0] != NULL);
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+
+ sta = sta_info_get(local, hdr->addr1);
+ lowest_idx = rate_lowest_index(local, sband, sta);
+ tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
+ /* lowest rate for management and multicast/broadcast frames */
+ if (!ieee80211_is_data(fc) ||
+ is_multicast_ether_addr(hdr->addr1) || !sta) {
+ sel->rate_idx = lowest_idx;
+ return;
+ }
+
+ ath_rc_priv = sta->rate_ctrl_priv;
+
+ /* Find tx rate for unicast frames */
+ ath_rate_findrate(sc, ath_rc_priv,
+ ATH_11N_TXMAXTRY, 4,
+ ATH_RC_PROBE_ALLOWED,
+ tx_info_priv->rcs,
+ &is_probe,
+ false);
+ if (is_probe)
+ sel->probe_idx = ((struct ath_tx_ratectrl *)
+ sta->rate_ctrl_priv)->probe_rate;
+
+ /* Ratecontrol sometimes returns invalid rate index */
+ if (tx_info_priv->rcs[0].rix != 0xff)
+ ath_rc_priv->prev_data_rix = tx_info_priv->rcs[0].rix;
+ else
+ tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix;
+
+ sel->rate_idx = tx_info_priv->rcs[0].rix;
+
+ /* Check if aggregation has to be enabled for this tid */
+
+ if (hw->conf.ht_conf.ht_supported) {
+ if (ieee80211_is_data_qos(fc)) {
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & 0xf;
+
+ spin_lock_bh(&sc->node_lock);
+ an = ath_node_find(sc, hdr->addr1);
+ spin_unlock_bh(&sc->node_lock);
+
+ if (!an) {
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: Node not found to "
+ "init/chk TX aggr\n", __func__);
+ return;
+ }
+
+ chk = ath_tx_aggr_check(sc, an, tid);
+ if (chk == AGGR_REQUIRED) {
+ ret = ieee80211_start_tx_ba_session(hw,
+ hdr->addr1, tid);
+ if (ret)
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: Unable to start tx "
+ "aggr for: %s\n",
+ __func__,
+ print_mac(mac, hdr->addr1));
+ else
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: Started tx aggr for: %s\n",
+ __func__,
+ print_mac(mac, hdr->addr1));
+ } else if (chk == AGGR_EXCHANGE_PROGRESS)
+ ath_tx_aggr_resp(sc, sta, an, tid);
+ }
+ }
+}
+
+static void ath_rate_init(void *priv, void *priv_sta,
+ struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_hw *hw = local_to_hw(local);
+ struct ieee80211_conf *conf = &local->hw.conf;
+ struct ath_softc *sc = hw->priv;
+ int i, j = 0;
+
+ DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
+
+ sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+ sta->txrate_idx = rate_lowest_index(local, sband, sta);
+
+ ath_setup_rates(local, sta);
+ if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
+ for (i = 0; i < MCS_SET_SIZE; i++) {
+ if (conf->ht_conf.supp_mcs_set[i/8] & (1<<(i%8)))
+ ((struct ath_rate_node *)
+ priv_sta)->neg_ht_rates.rs_rates[j++] = i;
+ if (j == ATH_RATE_MAX)
+ break;
+ }
+ ((struct ath_rate_node *)priv_sta)->neg_ht_rates.rs_nrates = j;
+ }
+ ath_rc_node_update(hw, priv_sta);
+}
+
+static void ath_rate_clear(void *priv)
+{
+ return;
+}
+
+static void *ath_rate_alloc(struct ieee80211_local *local)
+{
+ struct ieee80211_hw *hw = local_to_hw(local);
+ struct ath_softc *sc = hw->priv;
+
+ DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
+ return local->hw.priv;
+}
+
+static void ath_rate_free(void *priv)
+{
+ return;
+}
+
+static void *ath_rate_alloc_sta(void *priv, gfp_t gfp)
+{
+ struct ath_softc *sc = priv;
+ struct ath_vap *avp = sc->sc_vaps[0];
+ struct ath_rate_node *rate_priv;
+
+ DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
+ rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp);
+ if (!rate_priv) {
+ DPRINTF(sc, ATH_DBG_FATAL, "%s:Unable to allocate"
+ "private rate control structure", __func__);
+ return NULL;
+ }
+ ath_rc_sib_init(rate_priv);
+ return rate_priv;
+}
+
+static void ath_rate_free_sta(void *priv, void *priv_sta)
+{
+ struct ath_rate_node *rate_priv = priv_sta;
+ struct ath_softc *sc = priv;
+
+ DPRINTF(sc, ATH_DBG_RATE, "%s", __func__);
+ ath_rate_node_free(rate_priv);
+}
+
+static struct rate_control_ops ath_rate_ops = {
+ .module = NULL,
+ .name = "ath9k_rate_control",
+ .tx_status = ath_tx_status,
+ .get_rate = ath_get_rate,
+ .rate_init = ath_rate_init,
+ .clear = ath_rate_clear,
+ .alloc = ath_rate_alloc,
+ .free = ath_rate_free,
+ .alloc_sta = ath_rate_alloc_sta,
+ .free_sta = ath_rate_free_sta
+};
+
+int ath_rate_control_register(void)
+{
+ return ieee80211_rate_control_register(&ath_rate_ops);
+}
+
+void ath_rate_control_unregister(void)
+{
+ ieee80211_rate_control_unregister(&ath_rate_ops);
+}
+
diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h
new file mode 100644
index 00000000000..71aef9c7523
--- /dev/null
+++ b/drivers/net/wireless/ath9k/rc.h
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2004 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004 Video54 Technologies, Inc.
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef RC_H
+#define RC_H
+
+#include "ath9k.h"
+/*
+ * Interface definitions for transmit rate control modules for the
+ * Atheros driver.
+ *
+ * A rate control module is responsible for choosing the transmit rate
+ * for each data frame. Management+control frames are always sent at
+ * a fixed rate.
+ *
+ * Only one module may be present at a time; the driver references
+ * rate control interfaces by symbol name. If multiple modules are
+ * to be supported we'll need to switch to a registration-based scheme
+ * as is currently done, for example, for authentication modules.
+ *
+ * An instance of the rate control module is attached to each device
+ * at attach time and detached when the device is destroyed. The module
+ * may associate data with each device and each node (station). Both
+ * sets of storage are opaque except for the size of the per-node storage
+ * which must be provided when the module is attached.
+ *
+ * The rate control module is notified for each state transition and
+ * station association/reassociation. Otherwise it is queried for a
+ * rate for each outgoing frame and provided status from each transmitted
+ * frame. Any ancillary processing is the responsibility of the module
+ * (e.g. if periodic processing is required then the module should setup
+ * it's own timer).
+ *
+ * In addition to the transmit rate for each frame the module must also
+ * indicate the number of attempts to make at the specified rate. If this
+ * number is != ATH_TXMAXTRY then an additional callback is made to setup
+ * additional transmit state. The rate control code is assumed to write
+ * this additional data directly to the transmit descriptor.
+ */
+
+struct ath_softc;
+
+#define TRUE 1
+#define FALSE 0
+
+#define ATH_RATE_MAX 30
+#define MCS_SET_SIZE 128
+
+enum ieee80211_fixed_rate_mode {
+ IEEE80211_FIXED_RATE_NONE = 0,
+ IEEE80211_FIXED_RATE_MCS = 1 /* HT rates */
+};
+
+/*
+ * Use the hal os glue code to get ms time
+ */
+#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8)))
+
+#define SHORT_PRE 1
+#define LONG_PRE 0
+
+#define WLAN_PHY_HT_20_SS WLAN_RC_PHY_HT_20_SS
+#define WLAN_PHY_HT_20_DS WLAN_RC_PHY_HT_20_DS
+#define WLAN_PHY_HT_20_DS_HGI WLAN_RC_PHY_HT_20_DS_HGI
+#define WLAN_PHY_HT_40_SS WLAN_RC_PHY_HT_40_SS
+#define WLAN_PHY_HT_40_SS_HGI WLAN_RC_PHY_HT_40_SS_HGI
+#define WLAN_PHY_HT_40_DS WLAN_RC_PHY_HT_40_DS
+#define WLAN_PHY_HT_40_DS_HGI WLAN_RC_PHY_HT_40_DS_HGI
+
+#define WLAN_PHY_OFDM PHY_OFDM
+#define WLAN_PHY_CCK PHY_CCK
+
+#define TRUE_20 0x2
+#define TRUE_40 0x4
+#define TRUE_2040 (TRUE_20|TRUE_40)
+#define TRUE_ALL (TRUE_2040|TRUE)
+
+enum {
+ WLAN_RC_PHY_HT_20_SS = 4,
+ WLAN_RC_PHY_HT_20_DS,
+ WLAN_RC_PHY_HT_40_SS,
+ WLAN_RC_PHY_HT_40_DS,
+ WLAN_RC_PHY_HT_20_SS_HGI,
+ WLAN_RC_PHY_HT_20_DS_HGI,
+ WLAN_RC_PHY_HT_40_SS_HGI,
+ WLAN_RC_PHY_HT_40_DS_HGI,
+ WLAN_RC_PHY_MAX
+};
+
+#define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \
+ || (_phy == WLAN_RC_PHY_HT_40_DS) \
+ || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
+ || (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+#define WLAN_RC_PHY_40(_phy) ((_phy == WLAN_RC_PHY_HT_40_SS) \
+ || (_phy == WLAN_RC_PHY_HT_40_DS) \
+ || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
+ || (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+#define WLAN_RC_PHY_SGI(_phy) ((_phy == WLAN_RC_PHY_HT_20_SS_HGI) \
+ || (_phy == WLAN_RC_PHY_HT_20_DS_HGI) \
+ || (_phy == WLAN_RC_PHY_HT_40_SS_HGI) \
+ || (_phy == WLAN_RC_PHY_HT_40_DS_HGI))
+
+#define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS)
+
+/* Returns the capflag mode */
+#define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \
+ (capflag & WLAN_RC_40_FLAG) ? TRUE_40 : TRUE_20 : TRUE))
+
+/* Return TRUE if flag supports HT20 && client supports HT20 or
+ * return TRUE if flag supports HT40 && client supports HT40.
+ * This is used becos some rates overlap between HT20/HT40.
+ */
+
+#define WLAN_RC_PHY_HT_VALID(flag, capflag) (((flag & TRUE_20) && !(capflag \
+ & WLAN_RC_40_FLAG)) || ((flag & TRUE_40) && \
+ (capflag & WLAN_RC_40_FLAG)))
+
+#define WLAN_RC_DS_FLAG (0x01)
+#define WLAN_RC_40_FLAG (0x02)
+#define WLAN_RC_SGI_FLAG (0x04)
+#define WLAN_RC_HT_FLAG (0x08)
+
+/* Index into the rate table */
+#define INIT_RATE_MAX_20 23
+#define INIT_RATE_MAX_40 40
+
+#define RATE_TABLE_SIZE 64
+
+/* XXX: Convert to kdoc */
+struct ath_rate_table {
+ int rate_cnt;
+ struct {
+ int valid; /* Valid for use in rate control */
+ int valid_single_stream;/* Valid for use in rate control
+ for single stream operation */
+ u8 phy; /* CCK/OFDM/TURBO/XR */
+ u32 ratekbps; /* Rate in Kbits per second */
+ u32 user_ratekbps; /* User rate in KBits per second */
+ u8 ratecode; /* rate that goes into
+ hw descriptors */
+ u8 short_preamble; /* Mask for enabling short preamble
+ in rate code for CCK */
+ u8 dot11rate; /* Value that goes into supported
+ rates info element of MLME */
+ u8 ctrl_rate; /* Index of next lower basic rate,
+ used for duration computation */
+ int8_t rssi_ack_validmin; /* Rate control related */
+ int8_t rssi_ack_deltamin; /* Rate control related */
+ u8 base_index; /* base rate index */
+ u8 cw40index; /* 40cap rate index */
+ u8 sgi_index; /* shortgi rate index */
+ u8 ht_index; /* shortgi rate index */
+ u32 max_4ms_framelen; /* Maximum frame length(bytes)
+ for 4ms tx duration */
+ } info[RATE_TABLE_SIZE];
+ u32 probe_interval; /* interval for ratectrl to
+ probe for other rates */
+ u32 rssi_reduce_interval; /* interval for ratectrl
+ to reduce RSSI */
+ u8 initial_ratemax; /* the initial ratemax value used
+ in ath_rc_sib_update() */
+};
+
+#define ATH_RC_PROBE_ALLOWED 0x00000001
+#define ATH_RC_MINRATE_LASTRATE 0x00000002
+#define ATH_RC_SHORT_PREAMBLE 0x00000004
+
+struct ath_rc_series {
+ u8 rix;
+ u8 tries;
+ u8 flags;
+ u32 max_4ms_framelen;
+};
+
+/* rcs_flags definition */
+#define ATH_RC_DS_FLAG 0x01
+#define ATH_RC_CW40_FLAG 0x02 /* CW 40 */
+#define ATH_RC_SGI_FLAG 0x04 /* Short Guard Interval */
+#define ATH_RC_HT_FLAG 0x08 /* HT */
+#define ATH_RC_RTSCTS_FLAG 0x10 /* RTS-CTS */
+
+/*
+ * State structures for new rate adaptation code
+ */
+#define MAX_TX_RATE_TBL 64
+#define MAX_TX_RATE_PHY 48
+
+struct ath_tx_ratectrl_state {
+ int8_t rssi_thres; /* required rssi for this rate (dB) */
+ u8 per; /* recent estimate of packet error rate (%) */
+};
+
+struct ath_tx_ratectrl {
+ struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; /* state */
+ int8_t rssi_last; /* last ack rssi */
+ int8_t rssi_last_lookup; /* last ack rssi used for lookup */
+ int8_t rssi_last_prev; /* previous last ack rssi */
+ int8_t rssi_last_prev2; /* 2nd previous last ack rssi */
+ int32_t rssi_sum_cnt; /* count of rssi_sum for averaging */
+ int32_t rssi_sum_rate; /* rate that we are averaging */
+ int32_t rssi_sum; /* running sum of rssi for averaging */
+ u32 valid_txrate_mask; /* mask of valid rates */
+ u8 rate_table_size; /* rate table size */
+ u8 rate_max; /* max rate that has recently worked */
+ u8 probe_rate; /* rate we are probing at */
+ u32 rssi_time; /* msec timestamp for last ack rssi */
+ u32 rssi_down_time; /* msec timestamp for last down step */
+ u32 probe_time; /* msec timestamp for last probe */
+ u8 hw_maxretry_pktcnt; /* num packets since we got
+ HW max retry error */
+ u8 max_valid_rate; /* maximum number of valid rate */
+ u8 valid_rate_index[MAX_TX_RATE_TBL]; /* valid rate index */
+ u32 per_down_time; /* msec timstamp for last
+ PER down step */
+
+ /* 11n state */
+ u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; /* valid rate count */
+ u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL];
+ u8 rc_phy_mode;
+ u8 rate_max_phy; /* Phy index for the max rate */
+ u32 rate_max_lastused; /* msec timstamp of when we
+ last used rateMaxPhy */
+ u32 probe_interval; /* interval for ratectrl to probe
+ for other rates */
+};
+
+struct ath_rateset {
+ u8 rs_nrates;
+ u8 rs_rates[ATH_RATE_MAX];
+};
+
+/* per-device state */
+struct ath_rate_softc {
+ /* phy tables that contain rate control data */
+ const void *hw_rate_table[ATH9K_MODE_MAX];
+ int fixedrix; /* -1 or index of fixed rate */
+};
+
+/* per-node state */
+struct ath_rate_node {
+ struct ath_tx_ratectrl tx_ratectrl; /* rate control state proper */
+ u32 prev_data_rix; /* rate idx of last data frame */
+
+ /* map of rate ix -> negotiated rate set ix */
+ u8 rixmap[MAX_TX_RATE_TBL];
+
+ /* map of ht rate ix -> negotiated rate set ix */
+ u8 ht_rixmap[MAX_TX_RATE_TBL];
+
+ u8 ht_cap; /* ht capabilities */
+ u8 ant_tx; /* current transmit antenna */
+
+ u8 single_stream; /* When TRUE, only single
+ stream Tx possible */
+ struct ath_rateset neg_rates; /* Negotiated rates */
+ struct ath_rateset neg_ht_rates; /* Negotiated HT rates */
+ struct ath_rate_softc *asc; /* back pointer to atheros softc */
+ struct ath_vap *avp; /* back pointer to vap */
+};
+
+/* Driver data of ieee80211_tx_info */
+struct ath_tx_info_priv {
+ struct ath_rc_series rcs[4];
+ struct ath_tx_status tx;
+ int n_frames;
+ int n_bad_frames;
+ u8 min_rate;
+};
+
+/*
+ * Attach/detach a rate control module.
+ */
+struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah);
+void ath_rate_detach(struct ath_rate_softc *asc);
+
+/*
+ * Update/reset rate control state for 802.11 state transitions.
+ * Important mostly as the analog to ath_rate_newassoc when operating
+ * in station mode.
+ */
+void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv);
+void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp);
+
+/*
+ * Return the tx rate series.
+ */
+void ath_rate_findrate(struct ath_softc *sc, struct ath_rate_node *ath_rc_priv,
+ int num_tries, int num_rates,
+ unsigned int rcflag, struct ath_rc_series[],
+ int *is_probe, int isretry);
+/*
+ * Return rate index for given Dot11 Rate.
+ */
+u8 ath_rate_findrateix(struct ath_softc *sc,
+ u8 dot11_rate);
+
+/* Routines to register/unregister rate control algorithm */
+int ath_rate_control_register(void);
+void ath_rate_control_unregister(void);
+
+#endif /* RC_H */
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
new file mode 100644
index 00000000000..20ddb7acdb9
--- /dev/null
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -0,0 +1,1319 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Implementation of receive path.
+ */
+
+#include "core.h"
+
+/*
+ * Setup and link descriptors.
+ *
+ * 11N: we can no longer afford to self link the last descriptor.
+ * MAC acknowledges BA status as long as it copies frames to host
+ * buffer (or rx fifo). This can incorrectly acknowledge packets
+ * to a sender if last desc is self-linked.
+ *
+ * NOTE: Caller should hold the rxbuf lock.
+ */
+
+static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_desc *ds;
+ struct sk_buff *skb;
+
+ ATH_RXBUF_RESET(bf);
+
+ ds = bf->bf_desc;
+ ds->ds_link = 0; /* link to null */
+ ds->ds_data = bf->bf_buf_addr;
+
+ /* XXX For RADAR?
+ * virtual addr of the beginning of the buffer. */
+ skb = bf->bf_mpdu;
+ ASSERT(skb != NULL);
+ ds->ds_vdata = skb->data;
+
+ /* setup rx descriptors */
+ ath9k_hw_setuprxdesc(ah,
+ ds,
+ skb_tailroom(skb), /* buffer size */
+ 0);
+
+ if (sc->sc_rxlink == NULL)
+ ath9k_hw_putrxbuf(ah, bf->bf_daddr);
+ else
+ *sc->sc_rxlink = bf->bf_daddr;
+
+ sc->sc_rxlink = &ds->ds_link;
+ ath9k_hw_rxena(ah);
+}
+
+/* Process received BAR frame */
+
+static int ath_bar_rx(struct ath_softc *sc,
+ struct ath_node *an,
+ struct sk_buff *skb)
+{
+ struct ieee80211_bar *bar;
+ struct ath_arx_tid *rxtid;
+ struct sk_buff *tskb;
+ struct ath_recv_status *rx_status;
+ int tidno, index, cindex;
+ u16 seqno;
+
+ /* look at BAR contents */
+
+ bar = (struct ieee80211_bar *)skb->data;
+ tidno = (le16_to_cpu(bar->control) & IEEE80211_BAR_CTL_TID_M)
+ >> IEEE80211_BAR_CTL_TID_S;
+ seqno = le16_to_cpu(bar->start_seq_num) >> IEEE80211_SEQ_SEQ_SHIFT;
+
+ /* process BAR - indicate all pending RX frames till the BAR seqno */
+
+ rxtid = &an->an_aggr.rx.tid[tidno];
+
+ spin_lock_bh(&rxtid->tidlock);
+
+ /* get relative index */
+
+ index = ATH_BA_INDEX(rxtid->seq_next, seqno);
+
+ /* drop BAR if old sequence (index is too large) */
+
+ if ((index > rxtid->baw_size) &&
+ (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))))
+ /* discard frame, ieee layer may not treat frame as a dup */
+ goto unlock_and_free;
+
+ /* complete receive processing for all pending frames upto BAR seqno */
+
+ cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
+ while ((rxtid->baw_head != rxtid->baw_tail) &&
+ (rxtid->baw_head != cindex)) {
+ tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf;
+ rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status;
+ rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL;
+
+ if (tskb != NULL)
+ ath_rx_subframe(an, tskb, rx_status);
+
+ INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
+ INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
+ }
+
+ /* ... and indicate rest of the frames in-order */
+
+ while (rxtid->baw_head != rxtid->baw_tail &&
+ rxtid->rxbuf[rxtid->baw_head].rx_wbuf != NULL) {
+ tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf;
+ rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status;
+ rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL;
+
+ ath_rx_subframe(an, tskb, rx_status);
+
+ INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
+ INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
+ }
+
+unlock_and_free:
+ spin_unlock_bh(&rxtid->tidlock);
+ /* free bar itself */
+ dev_kfree_skb(skb);
+ return IEEE80211_FTYPE_CTL;
+}
+
+/* Function to handle a subframe of aggregation when HT is enabled */
+
+static int ath_ampdu_input(struct ath_softc *sc,
+ struct ath_node *an,
+ struct sk_buff *skb,
+ struct ath_recv_status *rx_status)
+{
+ struct ieee80211_hdr *hdr;
+ struct ath_arx_tid *rxtid;
+ struct ath_rxbuf *rxbuf;
+ u8 type, subtype;
+ u16 rxseq;
+ int tid = 0, index, cindex, rxdiff;
+ __le16 fc;
+ u8 *qc;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+
+ /* collect stats of frames with non-zero version */
+
+ if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_VERS) != 0) {
+ dev_kfree_skb(skb);
+ return -1;
+ }
+
+ type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
+ subtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE;
+
+ if (ieee80211_is_back_req(fc))
+ return ath_bar_rx(sc, an, skb);
+
+ /* special aggregate processing only for qos unicast data frames */
+
+ if (!ieee80211_is_data(fc) ||
+ !ieee80211_is_data_qos(fc) ||
+ is_multicast_ether_addr(hdr->addr1))
+ return ath_rx_subframe(an, skb, rx_status);
+
+ /* lookup rx tid state */
+
+ if (ieee80211_is_data_qos(fc)) {
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & 0xf;
+ }
+
+ if (sc->sc_opmode == ATH9K_M_STA) {
+ /* Drop the frame not belonging to me. */
+ if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) {
+ dev_kfree_skb(skb);
+ return -1;
+ }
+ }
+
+ rxtid = &an->an_aggr.rx.tid[tid];
+
+ spin_lock(&rxtid->tidlock);
+
+ rxdiff = (rxtid->baw_tail - rxtid->baw_head) &
+ (ATH_TID_MAX_BUFS - 1);
+
+ /*
+ * If the ADDBA exchange has not been completed by the source,
+ * process via legacy path (i.e. no reordering buffer is needed)
+ */
+ if (!rxtid->addba_exchangecomplete) {
+ spin_unlock(&rxtid->tidlock);
+ return ath_rx_subframe(an, skb, rx_status);
+ }
+
+ /* extract sequence number from recvd frame */
+
+ rxseq = le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
+
+ if (rxtid->seq_reset) {
+ rxtid->seq_reset = 0;
+ rxtid->seq_next = rxseq;
+ }
+
+ index = ATH_BA_INDEX(rxtid->seq_next, rxseq);
+
+ /* drop frame if old sequence (index is too large) */
+
+ if (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))) {
+ /* discard frame, ieee layer may not treat frame as a dup */
+ spin_unlock(&rxtid->tidlock);
+ dev_kfree_skb(skb);
+ return IEEE80211_FTYPE_DATA;
+ }
+
+ /* sequence number is beyond block-ack window */
+
+ if (index >= rxtid->baw_size) {
+
+ /* complete receive processing for all pending frames */
+
+ while (index >= rxtid->baw_size) {
+
+ rxbuf = rxtid->rxbuf + rxtid->baw_head;
+
+ if (rxbuf->rx_wbuf != NULL) {
+ ath_rx_subframe(an, rxbuf->rx_wbuf,
+ &rxbuf->rx_status);
+ rxbuf->rx_wbuf = NULL;
+ }
+
+ INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
+ INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
+
+ index--;
+ }
+ }
+
+ /* add buffer to the recv ba window */
+
+ cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
+ rxbuf = rxtid->rxbuf + cindex;
+
+ if (rxbuf->rx_wbuf != NULL) {
+ spin_unlock(&rxtid->tidlock);
+ /* duplicate frame */
+ dev_kfree_skb(skb);
+ return IEEE80211_FTYPE_DATA;
+ }
+
+ rxbuf->rx_wbuf = skb;
+ rxbuf->rx_time = get_timestamp();
+ rxbuf->rx_status = *rx_status;
+
+ /* advance tail if sequence received is newer
+ * than any received so far */
+
+ if (index >= rxdiff) {
+ rxtid->baw_tail = cindex;
+ INCR(rxtid->baw_tail, ATH_TID_MAX_BUFS);
+ }
+
+ /* indicate all in-order received frames */
+
+ while (rxtid->baw_head != rxtid->baw_tail) {
+ rxbuf = rxtid->rxbuf + rxtid->baw_head;
+ if (!rxbuf->rx_wbuf)
+ break;
+
+ ath_rx_subframe(an, rxbuf->rx_wbuf, &rxbuf->rx_status);
+ rxbuf->rx_wbuf = NULL;
+
+ INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
+ INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
+ }
+
+ /*
+ * start a timer to flush all received frames if there are pending
+ * receive frames
+ */
+ if (rxtid->baw_head != rxtid->baw_tail)
+ mod_timer(&rxtid->timer, ATH_RX_TIMEOUT);
+ else
+ del_timer_sync(&rxtid->timer);
+
+ spin_unlock(&rxtid->tidlock);
+ return IEEE80211_FTYPE_DATA;
+}
+
+/* Timer to flush all received sub-frames */
+
+static void ath_rx_timer(unsigned long data)
+{
+ struct ath_arx_tid *rxtid = (struct ath_arx_tid *)data;
+ struct ath_node *an = rxtid->an;
+ struct ath_rxbuf *rxbuf;
+ int nosched;
+
+ spin_lock_bh(&rxtid->tidlock);
+ while (rxtid->baw_head != rxtid->baw_tail) {
+ rxbuf = rxtid->rxbuf + rxtid->baw_head;
+ if (!rxbuf->rx_wbuf) {
+ INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
+ INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
+ continue;
+ }
+
+ /*
+ * Stop if the next one is a very recent frame.
+ *
+ * Call get_timestamp in every iteration to protect against the
+ * case in which a new frame is received while we are executing
+ * this function. Using a timestamp obtained before entering
+ * the loop could lead to a very large time interval
+ * (a negative value typecast to unsigned), breaking the
+ * function's logic.
+ */
+ if ((get_timestamp() - rxbuf->rx_time) <
+ (ATH_RX_TIMEOUT * HZ / 1000))
+ break;
+
+ ath_rx_subframe(an, rxbuf->rx_wbuf,
+ &rxbuf->rx_status);
+ rxbuf->rx_wbuf = NULL;
+
+ INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
+ INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
+ }
+
+ /*
+ * start a timer to flush all received frames if there are pending
+ * receive frames
+ */
+ if (rxtid->baw_head != rxtid->baw_tail)
+ nosched = 0;
+ else
+ nosched = 1; /* no need to re-arm the timer again */
+
+ spin_unlock_bh(&rxtid->tidlock);
+}
+
+/* Free all pending sub-frames in the re-ordering buffer */
+
+static void ath_rx_flush_tid(struct ath_softc *sc,
+ struct ath_arx_tid *rxtid, int drop)
+{
+ struct ath_rxbuf *rxbuf;
+ unsigned long flag;
+
+ spin_lock_irqsave(&rxtid->tidlock, flag);
+ while (rxtid->baw_head != rxtid->baw_tail) {
+ rxbuf = rxtid->rxbuf + rxtid->baw_head;
+ if (!rxbuf->rx_wbuf) {
+ INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
+ INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
+ continue;
+ }
+
+ if (drop)
+ dev_kfree_skb(rxbuf->rx_wbuf);
+ else
+ ath_rx_subframe(rxtid->an,
+ rxbuf->rx_wbuf,
+ &rxbuf->rx_status);
+
+ rxbuf->rx_wbuf = NULL;
+
+ INCR(rxtid->baw_head, ATH_TID_MAX_BUFS);
+ INCR(rxtid->seq_next, IEEE80211_SEQ_MAX);
+ }
+ spin_unlock_irqrestore(&rxtid->tidlock, flag);
+}
+
+static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc,
+ u32 len)
+{
+ struct sk_buff *skb;
+ u32 off;
+
+ /*
+ * Cache-line-align. This is important (for the
+ * 5210 at least) as not doing so causes bogus data
+ * in rx'd frames.
+ */
+
+ skb = dev_alloc_skb(len + sc->sc_cachelsz - 1);
+ if (skb != NULL) {
+ off = ((unsigned long) skb->data) % sc->sc_cachelsz;
+ if (off != 0)
+ skb_reserve(skb, sc->sc_cachelsz - off);
+ } else {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: skbuff alloc of size %u failed\n",
+ __func__, len);
+ return NULL;
+ }
+
+ return skb;
+}
+
+static void ath_rx_requeue(struct ath_softc *sc, struct sk_buff *skb)
+{
+ struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf;
+
+ ASSERT(bf != NULL);
+
+ spin_lock_bh(&sc->sc_rxbuflock);
+ if (bf->bf_status & ATH_BUFSTATUS_STALE) {
+ /*
+ * This buffer is still held for hw acess.
+ * Mark it as free to be re-queued it later.
+ */
+ bf->bf_status |= ATH_BUFSTATUS_FREE;
+ } else {
+ /* XXX: we probably never enter here, remove after
+ * verification */
+ list_add_tail(&bf->list, &sc->sc_rxbuf);
+ ath_rx_buf_link(sc, bf);
+ }
+ spin_unlock_bh(&sc->sc_rxbuflock);
+}
+
+/*
+ * The skb indicated to upper stack won't be returned to us.
+ * So we have to allocate a new one and queue it by ourselves.
+ */
+static int ath_rx_indicate(struct ath_softc *sc,
+ struct sk_buff *skb,
+ struct ath_recv_status *status,
+ u16 keyix)
+{
+ struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf;
+ struct sk_buff *nskb;
+ int type;
+
+ /* indicate frame to the stack, which will free the old skb. */
+ type = ath__rx_indicate(sc, skb, status, keyix);
+
+ /* allocate a new skb and queue it to for H/W processing */
+ nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
+ if (nskb != NULL) {
+ bf->bf_mpdu = nskb;
+ bf->bf_buf_addr = ath_skb_map_single(sc,
+ nskb,
+ PCI_DMA_FROMDEVICE,
+ /* XXX: Remove get_dma_mem_context() */
+ get_dma_mem_context(bf, bf_dmacontext));
+ ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf;
+
+ /* queue the new wbuf to H/W */
+ ath_rx_requeue(sc, nskb);
+ }
+
+ return type;
+}
+
+static void ath_opmode_init(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ u32 rfilt, mfilt[2];
+
+ /* configure rx filter */
+ rfilt = ath_calcrxfilter(sc);
+ ath9k_hw_setrxfilter(ah, rfilt);
+
+ /* configure bssid mask */
+ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+ ath9k_hw_setbssidmask(ah, sc->sc_bssidmask);
+
+ /* configure operational mode */
+ ath9k_hw_setopmode(ah);
+
+ /* Handle any link-level address change. */
+ ath9k_hw_setmac(ah, sc->sc_myaddr);
+
+ /* calculate and install multicast filter */
+ mfilt[0] = mfilt[1] = ~0;
+
+ ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
+ DPRINTF(sc, ATH_DBG_CONFIG ,
+ "%s: RX filter 0x%x, MC filter %08x:%08x\n",
+ __func__, rfilt, mfilt[0], mfilt[1]);
+}
+
+int ath_rx_init(struct ath_softc *sc, int nbufs)
+{
+ struct sk_buff *skb;
+ struct ath_buf *bf;
+ int error = 0;
+
+ do {
+ spin_lock_init(&sc->sc_rxflushlock);
+ sc->sc_rxflush = 0;
+ spin_lock_init(&sc->sc_rxbuflock);
+
+ /*
+ * Cisco's VPN software requires that drivers be able to
+ * receive encapsulated frames that are larger than the MTU.
+ * Since we can't be sure how large a frame we'll get, setup
+ * to handle the larges on possible.
+ */
+ sc->sc_rxbufsize = roundup(IEEE80211_MAX_MPDU_LEN,
+ min(sc->sc_cachelsz,
+ (u16)64));
+
+ DPRINTF(sc, ATH_DBG_CONFIG, "%s: cachelsz %u rxbufsize %u\n",
+ __func__, sc->sc_cachelsz, sc->sc_rxbufsize);
+
+ /* Initialize rx descriptors */
+
+ error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf,
+ "rx", nbufs, 1);
+ if (error != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: failed to allocate rx descriptors: %d\n",
+ __func__, error);
+ break;
+ }
+
+ /* Pre-allocate a wbuf for each rx buffer */
+
+ list_for_each_entry(bf, &sc->sc_rxbuf, list) {
+ skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize);
+ if (skb == NULL) {
+ error = -ENOMEM;
+ break;
+ }
+
+ bf->bf_mpdu = skb;
+ bf->bf_buf_addr =
+ ath_skb_map_single(sc, skb, PCI_DMA_FROMDEVICE,
+ get_dma_mem_context(bf, bf_dmacontext));
+ ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf;
+ }
+ sc->sc_rxlink = NULL;
+
+ } while (0);
+
+ if (error)
+ ath_rx_cleanup(sc);
+
+ return error;
+}
+
+/* Reclaim all rx queue resources */
+
+void ath_rx_cleanup(struct ath_softc *sc)
+{
+ struct sk_buff *skb;
+ struct ath_buf *bf;
+
+ list_for_each_entry(bf, &sc->sc_rxbuf, list) {
+ skb = bf->bf_mpdu;
+ if (skb)
+ dev_kfree_skb(skb);
+ }
+
+ /* cleanup rx descriptors */
+
+ if (sc->sc_rxdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
+}
+
+/*
+ * Calculate the receive filter according to the
+ * operating mode and state:
+ *
+ * o always accept unicast, broadcast, and multicast traffic
+ * o maintain current state of phy error reception (the hal
+ * may enable phy error frames for noise immunity work)
+ * o probe request frames are accepted only when operating in
+ * hostap, adhoc, or monitor modes
+ * o enable promiscuous mode according to the interface state
+ * o accept beacons:
+ * - when operating in adhoc mode so the 802.11 layer creates
+ * node table entries for peers,
+ * - when operating in station mode for collecting rssi data when
+ * the station is otherwise quiet, or
+ * - when operating as a repeater so we see repeater-sta beacons
+ * - when scanning
+ */
+
+u32 ath_calcrxfilter(struct ath_softc *sc)
+{
+#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
+ u32 rfilt;
+
+ rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE)
+ | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
+ | ATH9K_RX_FILTER_MCAST;
+
+ /* If not a STA, enable processing of Probe Requests */
+ if (sc->sc_opmode != ATH9K_M_STA)
+ rfilt |= ATH9K_RX_FILTER_PROBEREQ;
+
+ /* Can't set HOSTAP into promiscous mode */
+ if (sc->sc_opmode == ATH9K_M_MONITOR) {
+ rfilt |= ATH9K_RX_FILTER_PROM;
+ /* ??? To prevent from sending ACK */
+ rfilt &= ~ATH9K_RX_FILTER_UCAST;
+ }
+
+ if (sc->sc_opmode == ATH9K_M_STA || sc->sc_opmode == ATH9K_M_IBSS ||
+ sc->sc_scanning)
+ rfilt |= ATH9K_RX_FILTER_BEACON;
+
+ /* If in HOSTAP mode, want to enable reception of PSPOLL frames
+ & beacon frames */
+ if (sc->sc_opmode == ATH9K_M_HOSTAP)
+ rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
+ return rfilt;
+#undef RX_FILTER_PRESERVE
+}
+
+/* Enable the receive h/w following a reset. */
+
+int ath_startrecv(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf, *tbf;
+
+ spin_lock_bh(&sc->sc_rxbuflock);
+ if (list_empty(&sc->sc_rxbuf))
+ goto start_recv;
+
+ sc->sc_rxlink = NULL;
+ list_for_each_entry_safe(bf, tbf, &sc->sc_rxbuf, list) {
+ if (bf->bf_status & ATH_BUFSTATUS_STALE) {
+ /* restarting h/w, no need for holding descriptors */
+ bf->bf_status &= ~ATH_BUFSTATUS_STALE;
+ /*
+ * Upper layer may not be done with the frame yet so
+ * we can't just re-queue it to hardware. Remove it
+ * from h/w queue. It'll be re-queued when upper layer
+ * returns the frame and ath_rx_requeue_mpdu is called.
+ */
+ if (!(bf->bf_status & ATH_BUFSTATUS_FREE)) {
+ list_del(&bf->list);
+ continue;
+ }
+ }
+ /* chain descriptors */
+ ath_rx_buf_link(sc, bf);
+ }
+
+ /* We could have deleted elements so the list may be empty now */
+ if (list_empty(&sc->sc_rxbuf))
+ goto start_recv;
+
+ bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list);
+ ath9k_hw_putrxbuf(ah, bf->bf_daddr);
+ ath9k_hw_rxena(ah); /* enable recv descriptors */
+
+start_recv:
+ spin_unlock_bh(&sc->sc_rxbuflock);
+ ath_opmode_init(sc); /* set filters, etc. */
+ ath9k_hw_startpcureceive(ah); /* re-enable PCU/DMA engine */
+ return 0;
+}
+
+/* Disable the receive h/w in preparation for a reset. */
+
+bool ath_stoprecv(struct ath_softc *sc)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ u64 tsf;
+ bool stopped;
+
+ ath9k_hw_stoppcurecv(ah); /* disable PCU */
+ ath9k_hw_setrxfilter(ah, 0); /* clear recv filter */
+ stopped = ath9k_hw_stopdmarecv(ah); /* disable DMA engine */
+ mdelay(3); /* 3ms is long enough for 1 frame */
+ tsf = ath9k_hw_gettsf64(ah);
+ sc->sc_rxlink = NULL; /* just in case */
+ return stopped;
+}
+
+/* Flush receive queue */
+
+void ath_flushrecv(struct ath_softc *sc)
+{
+ /*
+ * ath_rx_tasklet may be used to handle rx interrupt and flush receive
+ * queue at the same time. Use a lock to serialize the access of rx
+ * queue.
+ * ath_rx_tasklet cannot hold the spinlock while indicating packets.
+ * Instead, do not claim the spinlock but check for a flush in
+ * progress (see references to sc_rxflush)
+ */
+ spin_lock_bh(&sc->sc_rxflushlock);
+ sc->sc_rxflush = 1;
+
+ ath_rx_tasklet(sc, 1);
+
+ sc->sc_rxflush = 0;
+ spin_unlock_bh(&sc->sc_rxflushlock);
+}
+
+/* Process an individual frame */
+
+int ath_rx_input(struct ath_softc *sc,
+ struct ath_node *an,
+ int is_ampdu,
+ struct sk_buff *skb,
+ struct ath_recv_status *rx_status,
+ enum ATH_RX_TYPE *status)
+{
+ if (is_ampdu && sc->sc_rxaggr) {
+ *status = ATH_RX_CONSUMED;
+ return ath_ampdu_input(sc, an, skb, rx_status);
+ } else {
+ *status = ATH_RX_NON_CONSUMED;
+ return -1;
+ }
+}
+
+/* Process receive queue, as well as LED, etc. */
+
+int ath_rx_tasklet(struct ath_softc *sc, int flush)
+{
+#define PA2DESC(_sc, _pa) \
+ ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \
+ ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr)))
+
+ struct ath_buf *bf, *bf_held = NULL;
+ struct ath_desc *ds;
+ struct ieee80211_hdr *hdr;
+ struct sk_buff *skb = NULL;
+ struct ath_recv_status rx_status;
+ struct ath_hal *ah = sc->sc_ah;
+ int type, rx_processed = 0;
+ u32 phyerr;
+ u8 chainreset = 0;
+ int retval;
+ __le16 fc;
+
+ do {
+ /* If handling rx interrupt and flush is in progress => exit */
+ if (sc->sc_rxflush && (flush == 0))
+ break;
+
+ spin_lock_bh(&sc->sc_rxbuflock);
+ if (list_empty(&sc->sc_rxbuf)) {
+ sc->sc_rxlink = NULL;
+ spin_unlock_bh(&sc->sc_rxbuflock);
+ break;
+ }
+
+ bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list);
+
+ /*
+ * There is a race condition that BH gets scheduled after sw
+ * writes RxE and before hw re-load the last descriptor to get
+ * the newly chained one. Software must keep the last DONE
+ * descriptor as a holding descriptor - software does so by
+ * marking it with the STALE flag.
+ */
+ if (bf->bf_status & ATH_BUFSTATUS_STALE) {
+ bf_held = bf;
+ if (list_is_last(&bf_held->list, &sc->sc_rxbuf)) {
+ /*
+ * The holding descriptor is the last
+ * descriptor in queue. It's safe to
+ * remove the last holding descriptor
+ * in BH context.
+ */
+ list_del(&bf_held->list);
+ bf_held->bf_status &= ~ATH_BUFSTATUS_STALE;
+ sc->sc_rxlink = NULL;
+
+ if (bf_held->bf_status & ATH_BUFSTATUS_FREE) {
+ list_add_tail(&bf_held->list,
+ &sc->sc_rxbuf);
+ ath_rx_buf_link(sc, bf_held);
+ }
+ spin_unlock_bh(&sc->sc_rxbuflock);
+ break;
+ }
+ bf = list_entry(bf->list.next, struct ath_buf, list);
+ }
+
+ ds = bf->bf_desc;
+ ++rx_processed;
+
+ /*
+ * Must provide the virtual address of the current
+ * descriptor, the physical address, and the virtual
+ * address of the next descriptor in the h/w chain.
+ * This allows the HAL to look ahead to see if the
+ * hardware is done with a descriptor by checking the
+ * done bit in the following descriptor and the address
+ * of the current descriptor the DMA engine is working
+ * on. All this is necessary because of our use of
+ * a self-linked list to avoid rx overruns.
+ */
+ retval = ath9k_hw_rxprocdesc(ah,
+ ds,
+ bf->bf_daddr,
+ PA2DESC(sc, ds->ds_link),
+ 0);
+ if (retval == -EINPROGRESS) {
+ struct ath_buf *tbf;
+ struct ath_desc *tds;
+
+ if (list_is_last(&bf->list, &sc->sc_rxbuf)) {
+ spin_unlock_bh(&sc->sc_rxbuflock);
+ break;
+ }
+
+ tbf = list_entry(bf->list.next, struct ath_buf, list);
+
+ /*
+ * On some hardware the descriptor status words could
+ * get corrupted, including the done bit. Because of
+ * this, check if the next descriptor's done bit is
+ * set or not.
+ *
+ * If the next descriptor's done bit is set, the current
+ * descriptor has been corrupted. Force s/w to discard
+ * this descriptor and continue...
+ */
+
+ tds = tbf->bf_desc;
+ retval = ath9k_hw_rxprocdesc(ah,
+ tds, tbf->bf_daddr,
+ PA2DESC(sc, tds->ds_link), 0);
+ if (retval == -EINPROGRESS) {
+ spin_unlock_bh(&sc->sc_rxbuflock);
+ break;
+ }
+ }
+
+ /* XXX: we do not support frames spanning
+ * multiple descriptors */
+ bf->bf_status |= ATH_BUFSTATUS_DONE;
+
+ skb = bf->bf_mpdu;
+ if (skb == NULL) { /* XXX ??? can this happen */
+ spin_unlock_bh(&sc->sc_rxbuflock);
+ continue;
+ }
+ /*
+ * Now we know it's a completed frame, we can indicate the
+ * frame. Remove the previous holding descriptor and leave
+ * this one in the queue as the new holding descriptor.
+ */
+ if (bf_held) {
+ list_del(&bf_held->list);
+ bf_held->bf_status &= ~ATH_BUFSTATUS_STALE;
+ if (bf_held->bf_status & ATH_BUFSTATUS_FREE) {
+ list_add_tail(&bf_held->list, &sc->sc_rxbuf);
+ /* try to requeue this descriptor */
+ ath_rx_buf_link(sc, bf_held);
+ }
+ }
+
+ bf->bf_status |= ATH_BUFSTATUS_STALE;
+ bf_held = bf;
+ /*
+ * Release the lock here in case ieee80211_input() return
+ * the frame immediately by calling ath_rx_mpdu_requeue().
+ */
+ spin_unlock_bh(&sc->sc_rxbuflock);
+
+ if (flush) {
+ /*
+ * If we're asked to flush receive queue, directly
+ * chain it back at the queue without processing it.
+ */
+ goto rx_next;
+ }
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+ memzero(&rx_status, sizeof(struct ath_recv_status));
+
+ if (ds->ds_rxstat.rs_more) {
+ /*
+ * Frame spans multiple descriptors; this
+ * cannot happen yet as we don't support
+ * jumbograms. If not in monitor mode,
+ * discard the frame.
+ */
+#ifndef ERROR_FRAMES
+ /*
+ * Enable this if you want to see
+ * error frames in Monitor mode.
+ */
+ if (sc->sc_opmode != ATH9K_M_MONITOR)
+ goto rx_next;
+#endif
+ /* fall thru for monitor mode handling... */
+ } else if (ds->ds_rxstat.rs_status != 0) {
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
+ rx_status.flags |= ATH_RX_FCS_ERROR;
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
+ phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
+ goto rx_next;
+ }
+
+ if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
+ /*
+ * Decrypt error. We only mark packet status
+ * here and always push up the frame up to let
+ * mac80211 handle the actual error case, be
+ * it no decryption key or real decryption
+ * error. This let us keep statistics there.
+ */
+ rx_status.flags |= ATH_RX_DECRYPT_ERROR;
+ } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
+ /*
+ * Demic error. We only mark frame status here
+ * and always push up the frame up to let
+ * mac80211 handle the actual error case. This
+ * let us keep statistics there. Hardware may
+ * post a false-positive MIC error.
+ */
+ if (ieee80211_is_ctl(fc))
+ /*
+ * Sometimes, we get invalid
+ * MIC failures on valid control frames.
+ * Remove these mic errors.
+ */
+ ds->ds_rxstat.rs_status &=
+ ~ATH9K_RXERR_MIC;
+ else
+ rx_status.flags |= ATH_RX_MIC_ERROR;
+ }
+ /*
+ * Reject error frames with the exception of
+ * decryption and MIC failures. For monitor mode,
+ * we also ignore the CRC error.
+ */
+ if (sc->sc_opmode == ATH9K_M_MONITOR) {
+ if (ds->ds_rxstat.rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+ ATH9K_RXERR_CRC))
+ goto rx_next;
+ } else {
+ if (ds->ds_rxstat.rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
+ goto rx_next;
+ }
+ }
+ }
+ /*
+ * The status portion of the descriptor could get corrupted.
+ */
+ if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen)
+ goto rx_next;
+ /*
+ * Sync and unmap the frame. At this point we're
+ * committed to passing the sk_buff somewhere so
+ * clear buf_skb; this means a new sk_buff must be
+ * allocated when the rx descriptor is setup again
+ * to receive another frame.
+ */
+ skb_put(skb, ds->ds_rxstat.rs_datalen);
+ skb->protocol = cpu_to_be16(ETH_P_CONTROL);
+ rx_status.tsf = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
+ rx_status.rateieee =
+ sc->sc_hwmap[ds->ds_rxstat.rs_rate].ieeerate;
+ rx_status.rateKbps =
+ sc->sc_hwmap[ds->ds_rxstat.rs_rate].rateKbps;
+ rx_status.ratecode = ds->ds_rxstat.rs_rate;
+
+ /* HT rate */
+ if (rx_status.ratecode & 0x80) {
+ /* TODO - add table to avoid division */
+ if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) {
+ rx_status.flags |= ATH_RX_40MHZ;
+ rx_status.rateKbps =
+ (rx_status.rateKbps * 27) / 13;
+ }
+ if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
+ rx_status.rateKbps =
+ (rx_status.rateKbps * 10) / 9;
+ else
+ rx_status.flags |= ATH_RX_SHORT_GI;
+ }
+
+ /* sc->sc_noise_floor is only available when the station
+ attaches to an AP, so we use a default value
+ if we are not yet attached. */
+
+ /* XXX we should use either sc->sc_noise_floor or
+ * ath_hal_getChanNoise(ah, &sc->sc_curchan)
+ * to calculate the noise floor.
+ * However, the value returned by ath_hal_getChanNoise
+ * seems to be incorrect (-31dBm on the last test),
+ * so we will use a hard-coded value until we
+ * figure out what is going on.
+ */
+ rx_status.abs_rssi =
+ ds->ds_rxstat.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
+
+ pci_dma_sync_single_for_cpu(sc->pdev,
+ bf->bf_buf_addr,
+ skb_tailroom(skb),
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_single(sc->pdev,
+ bf->bf_buf_addr,
+ sc->sc_rxbufsize,
+ PCI_DMA_FROMDEVICE);
+
+ /* XXX: Ah! make me more readable, use a helper */
+ if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) {
+ if (ds->ds_rxstat.rs_moreaggr == 0) {
+ rx_status.rssictl[0] =
+ ds->ds_rxstat.rs_rssi_ctl0;
+ rx_status.rssictl[1] =
+ ds->ds_rxstat.rs_rssi_ctl1;
+ rx_status.rssictl[2] =
+ ds->ds_rxstat.rs_rssi_ctl2;
+ rx_status.rssi = ds->ds_rxstat.rs_rssi;
+ if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) {
+ rx_status.rssiextn[0] =
+ ds->ds_rxstat.rs_rssi_ext0;
+ rx_status.rssiextn[1] =
+ ds->ds_rxstat.rs_rssi_ext1;
+ rx_status.rssiextn[2] =
+ ds->ds_rxstat.rs_rssi_ext2;
+ rx_status.flags |=
+ ATH_RX_RSSI_EXTN_VALID;
+ }
+ rx_status.flags |= ATH_RX_RSSI_VALID |
+ ATH_RX_CHAIN_RSSI_VALID;
+ }
+ } else {
+ /*
+ * Need to insert the "combined" rssi into the
+ * status structure for upper layer processing
+ */
+ rx_status.rssi = ds->ds_rxstat.rs_rssi;
+ rx_status.flags |= ATH_RX_RSSI_VALID;
+ }
+
+ /* Pass frames up to the stack. */
+
+ type = ath_rx_indicate(sc, skb,
+ &rx_status, ds->ds_rxstat.rs_keyix);
+
+ /*
+ * change the default rx antenna if rx diversity chooses the
+ * other antenna 3 times in a row.
+ */
+ if (sc->sc_defant != ds->ds_rxstat.rs_antenna) {
+ if (++sc->sc_rxotherant >= 3)
+ ath_setdefantenna(sc,
+ ds->ds_rxstat.rs_antenna);
+ } else {
+ sc->sc_rxotherant = 0;
+ }
+
+#ifdef CONFIG_SLOW_ANT_DIV
+ if ((rx_status.flags & ATH_RX_RSSI_VALID) &&
+ ieee80211_is_beacon(fc)) {
+ ath_slow_ant_div(&sc->sc_antdiv, hdr, &ds->ds_rxstat);
+ }
+#endif
+ /*
+ * For frames successfully indicated, the buffer will be
+ * returned to us by upper layers by calling
+ * ath_rx_mpdu_requeue, either synchronusly or asynchronously.
+ * So we don't want to do it here in this loop.
+ */
+ continue;
+
+rx_next:
+ bf->bf_status |= ATH_BUFSTATUS_FREE;
+ } while (TRUE);
+
+ if (chainreset) {
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "%s: Reset rx chain mask. "
+ "Do internal reset\n", __func__);
+ ASSERT(flush == 0);
+ ath_internal_reset(sc);
+ }
+
+ return 0;
+#undef PA2DESC
+}
+
+/* Process ADDBA request in per-TID data structure */
+
+int ath_rx_aggr_start(struct ath_softc *sc,
+ const u8 *addr,
+ u16 tid,
+ u16 *ssn)
+{
+ struct ath_arx_tid *rxtid;
+ struct ath_node *an;
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_supported_band *sband;
+ u16 buffersize = 0;
+
+ spin_lock_bh(&sc->node_lock);
+ an = ath_node_find(sc, (u8 *) addr);
+ spin_unlock_bh(&sc->node_lock);
+
+ if (!an) {
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: Node not found to initialize RX aggregation\n",
+ __func__);
+ return -1;
+ }
+
+ sband = hw->wiphy->bands[hw->conf.channel->band];
+ buffersize = IEEE80211_MIN_AMPDU_BUF <<
+ sband->ht_info.ampdu_factor; /* FIXME */
+
+ rxtid = &an->an_aggr.rx.tid[tid];
+
+ spin_lock_bh(&rxtid->tidlock);
+ if (sc->sc_rxaggr) {
+ /* Allow aggregation reception
+ * Adjust rx BA window size. Peer might indicate a
+ * zero buffer size for a _dont_care_ condition.
+ */
+ if (buffersize)
+ rxtid->baw_size = min(buffersize, rxtid->baw_size);
+
+ /* set rx sequence number */
+ rxtid->seq_next = *ssn;
+
+ /* Allocate the receive buffers for this TID */
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: Allcating rxbuffer for TID %d\n", __func__, tid);
+
+ if (rxtid->rxbuf == NULL) {
+ /*
+ * If the rxbuff is not NULL at this point, we *probably*
+ * already allocated the buffer on a previous ADDBA,
+ * and this is a subsequent ADDBA that got through.
+ * Don't allocate, but use the value in the pointer,
+ * we zero it out when we de-allocate.
+ */
+ rxtid->rxbuf = kmalloc(ATH_TID_MAX_BUFS *
+ sizeof(struct ath_rxbuf), GFP_ATOMIC);
+ }
+ if (rxtid->rxbuf == NULL) {
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: Unable to allocate RX buffer, "
+ "refusing ADDBA\n", __func__);
+ } else {
+ /* Ensure the memory is zeroed out (all internal
+ * pointers are null) */
+ memzero(rxtid->rxbuf, ATH_TID_MAX_BUFS *
+ sizeof(struct ath_rxbuf));
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: Allocated @%p\n", __func__, rxtid->rxbuf);
+
+ /* Allow aggregation reception */
+ rxtid->addba_exchangecomplete = 1;
+ }
+ }
+ spin_unlock_bh(&rxtid->tidlock);
+
+ return 0;
+}
+
+/* Process DELBA */
+
+int ath_rx_aggr_stop(struct ath_softc *sc,
+ const u8 *addr,
+ u16 tid)
+{
+ struct ath_node *an;
+
+ spin_lock_bh(&sc->node_lock);
+ an = ath_node_find(sc, (u8 *) addr);
+ spin_unlock_bh(&sc->node_lock);
+
+ if (!an) {
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: RX aggr stop for non-existent node\n", __func__);
+ return -1;
+ }
+
+ ath_rx_aggr_teardown(sc, an, tid);
+ return 0;
+}
+
+/* Rx aggregation tear down */
+
+void ath_rx_aggr_teardown(struct ath_softc *sc,
+ struct ath_node *an, u8 tid)
+{
+ struct ath_arx_tid *rxtid = &an->an_aggr.rx.tid[tid];
+
+ if (!rxtid->addba_exchangecomplete)
+ return;
+
+ del_timer_sync(&rxtid->timer);
+ ath_rx_flush_tid(sc, rxtid, 0);
+ rxtid->addba_exchangecomplete = 0;
+
+ /* De-allocate the receive buffer array allocated when addba started */
+
+ if (rxtid->rxbuf) {
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: Deallocating TID %d rxbuff @%p\n",
+ __func__, tid, rxtid->rxbuf);
+ kfree(rxtid->rxbuf);
+
+ /* Set pointer to null to avoid reuse*/
+ rxtid->rxbuf = NULL;
+ }
+}
+
+/* Initialize per-node receive state */
+
+void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an)
+{
+ if (sc->sc_rxaggr) {
+ struct ath_arx_tid *rxtid;
+ int tidno;
+
+ /* Init per tid rx state */
+ for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno];
+ tidno < WME_NUM_TID;
+ tidno++, rxtid++) {
+ rxtid->an = an;
+ rxtid->seq_reset = 1;
+ rxtid->seq_next = 0;
+ rxtid->baw_size = WME_MAX_BA;
+ rxtid->baw_head = rxtid->baw_tail = 0;
+
+ /*
+ * Ensure the buffer pointer is null at this point
+ * (needs to be allocated when addba is received)
+ */
+
+ rxtid->rxbuf = NULL;
+ setup_timer(&rxtid->timer, ath_rx_timer,
+ (unsigned long)rxtid);
+ spin_lock_init(&rxtid->tidlock);
+
+ /* ADDBA state */
+ rxtid->addba_exchangecomplete = 0;
+ }
+ }
+}
+
+void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
+{
+ if (sc->sc_rxaggr) {
+ struct ath_arx_tid *rxtid;
+ int tidno, i;
+
+ /* Init per tid rx state */
+ for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno];
+ tidno < WME_NUM_TID;
+ tidno++, rxtid++) {
+
+ if (!rxtid->addba_exchangecomplete)
+ continue;
+
+ /* must cancel timer first */
+ del_timer_sync(&rxtid->timer);
+
+ /* drop any pending sub-frames */
+ ath_rx_flush_tid(sc, rxtid, 1);
+
+ for (i = 0; i < ATH_TID_MAX_BUFS; i++)
+ ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL);
+
+ rxtid->addba_exchangecomplete = 0;
+ }
+ }
+
+}
+
+/* Cleanup per-node receive state */
+
+void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an)
+{
+ ath_rx_node_cleanup(sc, an);
+}
+
+dma_addr_t ath_skb_map_single(struct ath_softc *sc,
+ struct sk_buff *skb,
+ int direction,
+ dma_addr_t *pa)
+{
+ /*
+ * NB: do NOT use skb->len, which is 0 on initialization.
+ * Use skb's entire data area instead.
+ */
+ *pa = pci_map_single(sc->pdev, skb->data,
+ skb_end_pointer(skb) - skb->head, direction);
+ return *pa;
+}
+
+void ath_skb_unmap_single(struct ath_softc *sc,
+ struct sk_buff *skb,
+ int direction,
+ dma_addr_t *pa)
+{
+ /* Unmap skb's entire data area */
+ pci_unmap_single(sc->pdev, *pa,
+ skb_end_pointer(skb) - skb->head, direction);
+}
diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h
new file mode 100644
index 00000000000..42b0890a468
--- /dev/null
+++ b/drivers/net/wireless/ath9k/reg.h
@@ -0,0 +1,1385 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef REG_H
+#define REG_H
+
+#define AR_CR 0x0008
+#define AR_CR_RXE 0x00000004
+#define AR_CR_RXD 0x00000020
+#define AR_CR_SWI 0x00000040
+
+#define AR_RXDP 0x000C
+
+#define AR_CFG 0x0014
+#define AR_CFG_SWTD 0x00000001
+#define AR_CFG_SWTB 0x00000002
+#define AR_CFG_SWRD 0x00000004
+#define AR_CFG_SWRB 0x00000008
+#define AR_CFG_SWRG 0x00000010
+#define AR_CFG_AP_ADHOC_INDICATION 0x00000020
+#define AR_CFG_PHOK 0x00000100
+#define AR_CFG_CLK_GATE_DIS 0x00000400
+#define AR_CFG_EEBS 0x00000200
+#define AR_CFG_PCI_MASTER_REQ_Q_THRESH 0x00060000
+#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17
+
+#define AR_MIRT 0x0020
+#define AR_MIRT_VAL 0x0000ffff
+#define AR_MIRT_VAL_S 16
+
+#define AR_IER 0x0024
+#define AR_IER_ENABLE 0x00000001
+#define AR_IER_DISABLE 0x00000000
+
+#define AR_TIMT 0x0028
+#define AR_TIMT_LAST 0x0000ffff
+#define AR_TIMT_LAST_S 0
+#define AR_TIMT_FIRST 0xffff0000
+#define AR_TIMT_FIRST_S 16
+
+#define AR_RIMT 0x002C
+#define AR_RIMT_LAST 0x0000ffff
+#define AR_RIMT_LAST_S 0
+#define AR_RIMT_FIRST 0xffff0000
+#define AR_RIMT_FIRST_S 16
+
+#define AR_DMASIZE_4B 0x00000000
+#define AR_DMASIZE_8B 0x00000001
+#define AR_DMASIZE_16B 0x00000002
+#define AR_DMASIZE_32B 0x00000003
+#define AR_DMASIZE_64B 0x00000004
+#define AR_DMASIZE_128B 0x00000005
+#define AR_DMASIZE_256B 0x00000006
+#define AR_DMASIZE_512B 0x00000007
+
+#define AR_TXCFG 0x0030
+#define AR_TXCFG_DMASZ_MASK 0x00000003
+#define AR_TXCFG_DMASZ_4B 0
+#define AR_TXCFG_DMASZ_8B 1
+#define AR_TXCFG_DMASZ_16B 2
+#define AR_TXCFG_DMASZ_32B 3
+#define AR_TXCFG_DMASZ_64B 4
+#define AR_TXCFG_DMASZ_128B 5
+#define AR_TXCFG_DMASZ_256B 6
+#define AR_TXCFG_DMASZ_512B 7
+#define AR_FTRIG 0x000003F0
+#define AR_FTRIG_S 4
+#define AR_FTRIG_IMMED 0x00000000
+#define AR_FTRIG_64B 0x00000010
+#define AR_FTRIG_128B 0x00000020
+#define AR_FTRIG_192B 0x00000030
+#define AR_FTRIG_256B 0x00000040
+#define AR_FTRIG_512B 0x00000080
+#define AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY 0x00000800
+
+#define AR_RXCFG 0x0034
+#define AR_RXCFG_CHIRP 0x00000008
+#define AR_RXCFG_ZLFDMA 0x00000010
+#define AR_RXCFG_DMASZ_MASK 0x00000007
+#define AR_RXCFG_DMASZ_4B 0
+#define AR_RXCFG_DMASZ_8B 1
+#define AR_RXCFG_DMASZ_16B 2
+#define AR_RXCFG_DMASZ_32B 3
+#define AR_RXCFG_DMASZ_64B 4
+#define AR_RXCFG_DMASZ_128B 5
+#define AR_RXCFG_DMASZ_256B 6
+#define AR_RXCFG_DMASZ_512B 7
+
+#define AR_MIBC 0x0040
+#define AR_MIBC_COW 0x00000001
+#define AR_MIBC_FMC 0x00000002
+#define AR_MIBC_CMC 0x00000004
+#define AR_MIBC_MCS 0x00000008
+
+#define AR_TOPS 0x0044
+#define AR_TOPS_MASK 0x0000FFFF
+
+#define AR_RXNPTO 0x0048
+#define AR_RXNPTO_MASK 0x000003FF
+
+#define AR_TXNPTO 0x004C
+#define AR_TXNPTO_MASK 0x000003FF
+#define AR_TXNPTO_QCU_MASK 0x000FFC00
+
+#define AR_RPGTO 0x0050
+#define AR_RPGTO_MASK 0x000003FF
+
+#define AR_RPCNT 0x0054
+#define AR_RPCNT_MASK 0x0000001F
+
+#define AR_MACMISC 0x0058
+#define AR_MACMISC_PCI_EXT_FORCE 0x00000010
+#define AR_MACMISC_DMA_OBS 0x000001E0
+#define AR_MACMISC_DMA_OBS_S 5
+#define AR_MACMISC_DMA_OBS_LINE_0 0
+#define AR_MACMISC_DMA_OBS_LINE_1 1
+#define AR_MACMISC_DMA_OBS_LINE_2 2
+#define AR_MACMISC_DMA_OBS_LINE_3 3
+#define AR_MACMISC_DMA_OBS_LINE_4 4
+#define AR_MACMISC_DMA_OBS_LINE_5 5
+#define AR_MACMISC_DMA_OBS_LINE_6 6
+#define AR_MACMISC_DMA_OBS_LINE_7 7
+#define AR_MACMISC_DMA_OBS_LINE_8 8
+#define AR_MACMISC_MISC_OBS 0x00000E00
+#define AR_MACMISC_MISC_OBS_S 9
+#define AR_MACMISC_MISC_OBS_BUS_LSB 0x00007000
+#define AR_MACMISC_MISC_OBS_BUS_LSB_S 12
+#define AR_MACMISC_MISC_OBS_BUS_MSB 0x00038000
+#define AR_MACMISC_MISC_OBS_BUS_MSB_S 15
+#define AR_MACMISC_MISC_OBS_BUS_1 1
+
+#define AR_GTXTO 0x0064
+#define AR_GTXTO_TIMEOUT_COUNTER 0x0000FFFF
+#define AR_GTXTO_TIMEOUT_LIMIT 0xFFFF0000
+#define AR_GTXTO_TIMEOUT_LIMIT_S 16
+
+#define AR_GTTM 0x0068
+#define AR_GTTM_USEC 0x00000001
+#define AR_GTTM_IGNORE_IDLE 0x00000002
+#define AR_GTTM_RESET_IDLE 0x00000004
+#define AR_GTTM_CST_USEC 0x00000008
+
+#define AR_CST 0x006C
+#define AR_CST_TIMEOUT_COUNTER 0x0000FFFF
+#define AR_CST_TIMEOUT_LIMIT 0xFFFF0000
+#define AR_CST_TIMEOUT_LIMIT_S 16
+
+#define AR_SREV_VERSION_9100 0x014
+
+#define AR_SREV_5416_V20_OR_LATER(_ah) \
+ (AR_SREV_9100((_ah)) || AR_SREV_5416_20_OR_LATER(_ah))
+#define AR_SREV_5416_V22_OR_LATER(_ah) \
+ (AR_SREV_9100((_ah)) || AR_SREV_5416_22_OR_LATER(_ah))
+
+#define AR_ISR 0x0080
+#define AR_ISR_RXOK 0x00000001
+#define AR_ISR_RXDESC 0x00000002
+#define AR_ISR_RXERR 0x00000004
+#define AR_ISR_RXNOPKT 0x00000008
+#define AR_ISR_RXEOL 0x00000010
+#define AR_ISR_RXORN 0x00000020
+#define AR_ISR_TXOK 0x00000040
+#define AR_ISR_TXDESC 0x00000080
+#define AR_ISR_TXERR 0x00000100
+#define AR_ISR_TXNOPKT 0x00000200
+#define AR_ISR_TXEOL 0x00000400
+#define AR_ISR_TXURN 0x00000800
+#define AR_ISR_MIB 0x00001000
+#define AR_ISR_SWI 0x00002000
+#define AR_ISR_RXPHY 0x00004000
+#define AR_ISR_RXKCM 0x00008000
+#define AR_ISR_SWBA 0x00010000
+#define AR_ISR_BRSSI 0x00020000
+#define AR_ISR_BMISS 0x00040000
+#define AR_ISR_BNR 0x00100000
+#define AR_ISR_RXCHIRP 0x00200000
+#define AR_ISR_BCNMISC 0x00800000
+#define AR_ISR_TIM 0x00800000
+#define AR_ISR_QCBROVF 0x02000000
+#define AR_ISR_QCBRURN 0x04000000
+#define AR_ISR_QTRIG 0x08000000
+#define AR_ISR_GENTMR 0x10000000
+
+#define AR_ISR_TXMINTR 0x00080000
+#define AR_ISR_RXMINTR 0x01000000
+#define AR_ISR_TXINTM 0x40000000
+#define AR_ISR_RXINTM 0x80000000
+
+#define AR_ISR_S0 0x0084
+#define AR_ISR_S0_QCU_TXOK 0x000003FF
+#define AR_ISR_S0_QCU_TXOK_S 0
+#define AR_ISR_S0_QCU_TXDESC 0x03FF0000
+#define AR_ISR_S0_QCU_TXDESC_S 16
+
+#define AR_ISR_S1 0x0088
+#define AR_ISR_S1_QCU_TXERR 0x000003FF
+#define AR_ISR_S1_QCU_TXERR_S 0
+#define AR_ISR_S1_QCU_TXEOL 0x03FF0000
+#define AR_ISR_S1_QCU_TXEOL_S 16
+
+#define AR_ISR_S2 0x008c
+#define AR_ISR_S2_QCU_TXURN 0x000003FF
+#define AR_ISR_S2_CST 0x00400000
+#define AR_ISR_S2_GTT 0x00800000
+#define AR_ISR_S2_TIM 0x01000000
+#define AR_ISR_S2_CABEND 0x02000000
+#define AR_ISR_S2_DTIMSYNC 0x04000000
+#define AR_ISR_S2_BCNTO 0x08000000
+#define AR_ISR_S2_CABTO 0x10000000
+#define AR_ISR_S2_DTIM 0x20000000
+#define AR_ISR_S2_TSFOOR 0x40000000
+#define AR_ISR_S2_TBTT_TIME 0x80000000
+
+#define AR_ISR_S3 0x0090
+#define AR_ISR_S3_QCU_QCBROVF 0x000003FF
+#define AR_ISR_S3_QCU_QCBRURN 0x03FF0000
+
+#define AR_ISR_S4 0x0094
+#define AR_ISR_S4_QCU_QTRIG 0x000003FF
+#define AR_ISR_S4_RESV0 0xFFFFFC00
+
+#define AR_ISR_S5 0x0098
+#define AR_ISR_S5_TIMER_TRIG 0x000000FF
+#define AR_ISR_S5_TIMER_THRESH 0x0007FE00
+#define AR_ISR_S5_TIM_TIMER 0x00000010
+#define AR_ISR_S5_DTIM_TIMER 0x00000020
+#define AR_ISR_S5_S 0x00d8
+#define AR_IMR_S5 0x00b8
+#define AR_IMR_S5_TIM_TIMER 0x00000010
+#define AR_IMR_S5_DTIM_TIMER 0x00000020
+
+
+#define AR_IMR 0x00a0
+#define AR_IMR_RXOK 0x00000001
+#define AR_IMR_RXDESC 0x00000002
+#define AR_IMR_RXERR 0x00000004
+#define AR_IMR_RXNOPKT 0x00000008
+#define AR_IMR_RXEOL 0x00000010
+#define AR_IMR_RXORN 0x00000020
+#define AR_IMR_TXOK 0x00000040
+#define AR_IMR_TXDESC 0x00000080
+#define AR_IMR_TXERR 0x00000100
+#define AR_IMR_TXNOPKT 0x00000200
+#define AR_IMR_TXEOL 0x00000400
+#define AR_IMR_TXURN 0x00000800
+#define AR_IMR_MIB 0x00001000
+#define AR_IMR_SWI 0x00002000
+#define AR_IMR_RXPHY 0x00004000
+#define AR_IMR_RXKCM 0x00008000
+#define AR_IMR_SWBA 0x00010000
+#define AR_IMR_BRSSI 0x00020000
+#define AR_IMR_BMISS 0x00040000
+#define AR_IMR_BNR 0x00100000
+#define AR_IMR_RXCHIRP 0x00200000
+#define AR_IMR_BCNMISC 0x00800000
+#define AR_IMR_TIM 0x00800000
+#define AR_IMR_QCBROVF 0x02000000
+#define AR_IMR_QCBRURN 0x04000000
+#define AR_IMR_QTRIG 0x08000000
+#define AR_IMR_GENTMR 0x10000000
+
+#define AR_IMR_TXMINTR 0x00080000
+#define AR_IMR_RXMINTR 0x01000000
+#define AR_IMR_TXINTM 0x40000000
+#define AR_IMR_RXINTM 0x80000000
+
+#define AR_IMR_S0 0x00a4
+#define AR_IMR_S0_QCU_TXOK 0x000003FF
+#define AR_IMR_S0_QCU_TXOK_S 0
+#define AR_IMR_S0_QCU_TXDESC 0x03FF0000
+#define AR_IMR_S0_QCU_TXDESC_S 16
+
+#define AR_IMR_S1 0x00a8
+#define AR_IMR_S1_QCU_TXERR 0x000003FF
+#define AR_IMR_S1_QCU_TXERR_S 0
+#define AR_IMR_S1_QCU_TXEOL 0x03FF0000
+#define AR_IMR_S1_QCU_TXEOL_S 16
+
+#define AR_IMR_S2 0x00ac
+#define AR_IMR_S2_QCU_TXURN 0x000003FF
+#define AR_IMR_S2_QCU_TXURN_S 0
+#define AR_IMR_S2_CST 0x00400000
+#define AR_IMR_S2_GTT 0x00800000
+#define AR_IMR_S2_TIM 0x01000000
+#define AR_IMR_S2_CABEND 0x02000000
+#define AR_IMR_S2_DTIMSYNC 0x04000000
+#define AR_IMR_S2_BCNTO 0x08000000
+#define AR_IMR_S2_CABTO 0x10000000
+#define AR_IMR_S2_DTIM 0x20000000
+#define AR_IMR_S2_TSFOOR 0x40000000
+
+#define AR_IMR_S3 0x00b0
+#define AR_IMR_S3_QCU_QCBROVF 0x000003FF
+#define AR_IMR_S3_QCU_QCBRURN 0x03FF0000
+#define AR_IMR_S3_QCU_QCBRURN_S 16
+
+#define AR_IMR_S4 0x00b4
+#define AR_IMR_S4_QCU_QTRIG 0x000003FF
+#define AR_IMR_S4_RESV0 0xFFFFFC00
+
+#define AR_IMR_S5 0x00b8
+#define AR_IMR_S5_TIMER_TRIG 0x000000FF
+#define AR_IMR_S5_TIMER_THRESH 0x0000FF00
+
+
+#define AR_ISR_RAC 0x00c0
+#define AR_ISR_S0_S 0x00c4
+#define AR_ISR_S0_QCU_TXOK 0x000003FF
+#define AR_ISR_S0_QCU_TXOK_S 0
+#define AR_ISR_S0_QCU_TXDESC 0x03FF0000
+#define AR_ISR_S0_QCU_TXDESC_S 16
+
+#define AR_ISR_S1_S 0x00c8
+#define AR_ISR_S1_QCU_TXERR 0x000003FF
+#define AR_ISR_S1_QCU_TXERR_S 0
+#define AR_ISR_S1_QCU_TXEOL 0x03FF0000
+#define AR_ISR_S1_QCU_TXEOL_S 16
+
+#define AR_ISR_S2_S 0x00cc
+#define AR_ISR_S3_S 0x00d0
+#define AR_ISR_S4_S 0x00d4
+#define AR_ISR_S5_S 0x00d8
+#define AR_DMADBG_0 0x00e0
+#define AR_DMADBG_1 0x00e4
+#define AR_DMADBG_2 0x00e8
+#define AR_DMADBG_3 0x00ec
+#define AR_DMADBG_4 0x00f0
+#define AR_DMADBG_5 0x00f4
+#define AR_DMADBG_6 0x00f8
+#define AR_DMADBG_7 0x00fc
+
+#define AR_NUM_QCU 10
+#define AR_QCU_0 0x0001
+#define AR_QCU_1 0x0002
+#define AR_QCU_2 0x0004
+#define AR_QCU_3 0x0008
+#define AR_QCU_4 0x0010
+#define AR_QCU_5 0x0020
+#define AR_QCU_6 0x0040
+#define AR_QCU_7 0x0080
+#define AR_QCU_8 0x0100
+#define AR_QCU_9 0x0200
+
+#define AR_Q0_TXDP 0x0800
+#define AR_Q1_TXDP 0x0804
+#define AR_Q2_TXDP 0x0808
+#define AR_Q3_TXDP 0x080c
+#define AR_Q4_TXDP 0x0810
+#define AR_Q5_TXDP 0x0814
+#define AR_Q6_TXDP 0x0818
+#define AR_Q7_TXDP 0x081c
+#define AR_Q8_TXDP 0x0820
+#define AR_Q9_TXDP 0x0824
+#define AR_QTXDP(_i) (AR_Q0_TXDP + ((_i)<<2))
+
+#define AR_Q_TXE 0x0840
+#define AR_Q_TXE_M 0x000003FF
+
+#define AR_Q_TXD 0x0880
+#define AR_Q_TXD_M 0x000003FF
+
+#define AR_Q0_CBRCFG 0x08c0
+#define AR_Q1_CBRCFG 0x08c4
+#define AR_Q2_CBRCFG 0x08c8
+#define AR_Q3_CBRCFG 0x08cc
+#define AR_Q4_CBRCFG 0x08d0
+#define AR_Q5_CBRCFG 0x08d4
+#define AR_Q6_CBRCFG 0x08d8
+#define AR_Q7_CBRCFG 0x08dc
+#define AR_Q8_CBRCFG 0x08e0
+#define AR_Q9_CBRCFG 0x08e4
+#define AR_QCBRCFG(_i) (AR_Q0_CBRCFG + ((_i)<<2))
+#define AR_Q_CBRCFG_INTERVAL 0x00FFFFFF
+#define AR_Q_CBRCFG_INTERVAL_S 0
+#define AR_Q_CBRCFG_OVF_THRESH 0xFF000000
+#define AR_Q_CBRCFG_OVF_THRESH_S 24
+
+#define AR_Q0_RDYTIMECFG 0x0900
+#define AR_Q1_RDYTIMECFG 0x0904
+#define AR_Q2_RDYTIMECFG 0x0908
+#define AR_Q3_RDYTIMECFG 0x090c
+#define AR_Q4_RDYTIMECFG 0x0910
+#define AR_Q5_RDYTIMECFG 0x0914
+#define AR_Q6_RDYTIMECFG 0x0918
+#define AR_Q7_RDYTIMECFG 0x091c
+#define AR_Q8_RDYTIMECFG 0x0920
+#define AR_Q9_RDYTIMECFG 0x0924
+#define AR_QRDYTIMECFG(_i) (AR_Q0_RDYTIMECFG + ((_i)<<2))
+#define AR_Q_RDYTIMECFG_DURATION 0x00FFFFFF
+#define AR_Q_RDYTIMECFG_DURATION_S 0
+#define AR_Q_RDYTIMECFG_EN 0x01000000
+
+#define AR_Q_ONESHOTARM_SC 0x0940
+#define AR_Q_ONESHOTARM_SC_M 0x000003FF
+#define AR_Q_ONESHOTARM_SC_RESV0 0xFFFFFC00
+
+#define AR_Q_ONESHOTARM_CC 0x0980
+#define AR_Q_ONESHOTARM_CC_M 0x000003FF
+#define AR_Q_ONESHOTARM_CC_RESV0 0xFFFFFC00
+
+#define AR_Q0_MISC 0x09c0
+#define AR_Q1_MISC 0x09c4
+#define AR_Q2_MISC 0x09c8
+#define AR_Q3_MISC 0x09cc
+#define AR_Q4_MISC 0x09d0
+#define AR_Q5_MISC 0x09d4
+#define AR_Q6_MISC 0x09d8
+#define AR_Q7_MISC 0x09dc
+#define AR_Q8_MISC 0x09e0
+#define AR_Q9_MISC 0x09e4
+#define AR_QMISC(_i) (AR_Q0_MISC + ((_i)<<2))
+#define AR_Q_MISC_FSP 0x0000000F
+#define AR_Q_MISC_FSP_ASAP 0
+#define AR_Q_MISC_FSP_CBR 1
+#define AR_Q_MISC_FSP_DBA_GATED 2
+#define AR_Q_MISC_FSP_TIM_GATED 3
+#define AR_Q_MISC_FSP_BEACON_SENT_GATED 4
+#define AR_Q_MISC_FSP_BEACON_RCVD_GATED 5
+#define AR_Q_MISC_ONE_SHOT_EN 0x00000010
+#define AR_Q_MISC_CBR_INCR_DIS1 0x00000020
+#define AR_Q_MISC_CBR_INCR_DIS0 0x00000040
+#define AR_Q_MISC_BEACON_USE 0x00000080
+#define AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN 0x00000100
+#define AR_Q_MISC_RDYTIME_EXP_POLICY 0x00000200
+#define AR_Q_MISC_RESET_CBR_EXP_CTR 0x00000400
+#define AR_Q_MISC_DCU_EARLY_TERM_REQ 0x00000800
+#define AR_Q_MISC_RESV0 0xFFFFF000
+
+#define AR_Q0_STS 0x0a00
+#define AR_Q1_STS 0x0a04
+#define AR_Q2_STS 0x0a08
+#define AR_Q3_STS 0x0a0c
+#define AR_Q4_STS 0x0a10
+#define AR_Q5_STS 0x0a14
+#define AR_Q6_STS 0x0a18
+#define AR_Q7_STS 0x0a1c
+#define AR_Q8_STS 0x0a20
+#define AR_Q9_STS 0x0a24
+#define AR_QSTS(_i) (AR_Q0_STS + ((_i)<<2))
+#define AR_Q_STS_PEND_FR_CNT 0x00000003
+#define AR_Q_STS_RESV0 0x000000FC
+#define AR_Q_STS_CBR_EXP_CNT 0x0000FF00
+#define AR_Q_STS_RESV1 0xFFFF0000
+
+#define AR_Q_RDYTIMESHDN 0x0a40
+#define AR_Q_RDYTIMESHDN_M 0x000003FF
+
+
+#define AR_NUM_DCU 10
+#define AR_DCU_0 0x0001
+#define AR_DCU_1 0x0002
+#define AR_DCU_2 0x0004
+#define AR_DCU_3 0x0008
+#define AR_DCU_4 0x0010
+#define AR_DCU_5 0x0020
+#define AR_DCU_6 0x0040
+#define AR_DCU_7 0x0080
+#define AR_DCU_8 0x0100
+#define AR_DCU_9 0x0200
+
+#define AR_D0_QCUMASK 0x1000
+#define AR_D1_QCUMASK 0x1004
+#define AR_D2_QCUMASK 0x1008
+#define AR_D3_QCUMASK 0x100c
+#define AR_D4_QCUMASK 0x1010
+#define AR_D5_QCUMASK 0x1014
+#define AR_D6_QCUMASK 0x1018
+#define AR_D7_QCUMASK 0x101c
+#define AR_D8_QCUMASK 0x1020
+#define AR_D9_QCUMASK 0x1024
+#define AR_DQCUMASK(_i) (AR_D0_QCUMASK + ((_i)<<2))
+#define AR_D_QCUMASK 0x000003FF
+#define AR_D_QCUMASK_RESV0 0xFFFFFC00
+
+#define AR_D_TXBLK_CMD 0x1038
+#define AR_D_TXBLK_DATA(i) (AR_D_TXBLK_CMD+(i))
+
+#define AR_D0_LCL_IFS 0x1040
+#define AR_D1_LCL_IFS 0x1044
+#define AR_D2_LCL_IFS 0x1048
+#define AR_D3_LCL_IFS 0x104c
+#define AR_D4_LCL_IFS 0x1050
+#define AR_D5_LCL_IFS 0x1054
+#define AR_D6_LCL_IFS 0x1058
+#define AR_D7_LCL_IFS 0x105c
+#define AR_D8_LCL_IFS 0x1060
+#define AR_D9_LCL_IFS 0x1064
+#define AR_DLCL_IFS(_i) (AR_D0_LCL_IFS + ((_i)<<2))
+#define AR_D_LCL_IFS_CWMIN 0x000003FF
+#define AR_D_LCL_IFS_CWMIN_S 0
+#define AR_D_LCL_IFS_CWMAX 0x000FFC00
+#define AR_D_LCL_IFS_CWMAX_S 10
+#define AR_D_LCL_IFS_AIFS 0x0FF00000
+#define AR_D_LCL_IFS_AIFS_S 20
+
+#define AR_D_LCL_IFS_RESV0 0xF0000000
+
+#define AR_D0_RETRY_LIMIT 0x1080
+#define AR_D1_RETRY_LIMIT 0x1084
+#define AR_D2_RETRY_LIMIT 0x1088
+#define AR_D3_RETRY_LIMIT 0x108c
+#define AR_D4_RETRY_LIMIT 0x1090
+#define AR_D5_RETRY_LIMIT 0x1094
+#define AR_D6_RETRY_LIMIT 0x1098
+#define AR_D7_RETRY_LIMIT 0x109c
+#define AR_D8_RETRY_LIMIT 0x10a0
+#define AR_D9_RETRY_LIMIT 0x10a4
+#define AR_DRETRY_LIMIT(_i) (AR_D0_RETRY_LIMIT + ((_i)<<2))
+#define AR_D_RETRY_LIMIT_FR_SH 0x0000000F
+#define AR_D_RETRY_LIMIT_FR_SH_S 0
+#define AR_D_RETRY_LIMIT_STA_SH 0x00003F00
+#define AR_D_RETRY_LIMIT_STA_SH_S 8
+#define AR_D_RETRY_LIMIT_STA_LG 0x000FC000
+#define AR_D_RETRY_LIMIT_STA_LG_S 14
+#define AR_D_RETRY_LIMIT_RESV0 0xFFF00000
+
+#define AR_D0_CHNTIME 0x10c0
+#define AR_D1_CHNTIME 0x10c4
+#define AR_D2_CHNTIME 0x10c8
+#define AR_D3_CHNTIME 0x10cc
+#define AR_D4_CHNTIME 0x10d0
+#define AR_D5_CHNTIME 0x10d4
+#define AR_D6_CHNTIME 0x10d8
+#define AR_D7_CHNTIME 0x10dc
+#define AR_D8_CHNTIME 0x10e0
+#define AR_D9_CHNTIME 0x10e4
+#define AR_DCHNTIME(_i) (AR_D0_CHNTIME + ((_i)<<2))
+#define AR_D_CHNTIME_DUR 0x000FFFFF
+#define AR_D_CHNTIME_DUR_S 0
+#define AR_D_CHNTIME_EN 0x00100000
+#define AR_D_CHNTIME_RESV0 0xFFE00000
+
+#define AR_D0_MISC 0x1100
+#define AR_D1_MISC 0x1104
+#define AR_D2_MISC 0x1108
+#define AR_D3_MISC 0x110c
+#define AR_D4_MISC 0x1110
+#define AR_D5_MISC 0x1114
+#define AR_D6_MISC 0x1118
+#define AR_D7_MISC 0x111c
+#define AR_D8_MISC 0x1120
+#define AR_D9_MISC 0x1124
+#define AR_DMISC(_i) (AR_D0_MISC + ((_i)<<2))
+#define AR_D_MISC_BKOFF_THRESH 0x0000003F
+#define AR_D_MISC_RETRY_CNT_RESET_EN 0x00000040
+#define AR_D_MISC_CW_RESET_EN 0x00000080
+#define AR_D_MISC_FRAG_WAIT_EN 0x00000100
+#define AR_D_MISC_FRAG_BKOFF_EN 0x00000200
+#define AR_D_MISC_CW_BKOFF_EN 0x00001000
+#define AR_D_MISC_VIR_COL_HANDLING 0x0000C000
+#define AR_D_MISC_VIR_COL_HANDLING_S 14
+#define AR_D_MISC_VIR_COL_HANDLING_DEFAULT 0
+#define AR_D_MISC_VIR_COL_HANDLING_IGNORE 1
+#define AR_D_MISC_BEACON_USE 0x00010000
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL 0x00060000
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_S 17
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_NONE 0
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_INTRA_FR 1
+#define AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL 2
+#define AR_D_MISC_ARB_LOCKOUT_IGNORE 0x00080000
+#define AR_D_MISC_SEQ_NUM_INCR_DIS 0x00100000
+#define AR_D_MISC_POST_FR_BKOFF_DIS 0x00200000
+#define AR_D_MISC_VIT_COL_CW_BKOFF_EN 0x00400000
+#define AR_D_MISC_BLOWN_IFS_RETRY_EN 0x00800000
+#define AR_D_MISC_RESV0 0xFF000000
+
+#define AR_D_SEQNUM 0x1140
+
+#define AR_D_GBL_IFS_SIFS 0x1030
+#define AR_D_GBL_IFS_SIFS_M 0x0000FFFF
+#define AR_D_GBL_IFS_SIFS_RESV0 0xFFFFFFFF
+
+#define AR_D_TXBLK_BASE 0x1038
+#define AR_D_TXBLK_WRITE_BITMASK 0x0000FFFF
+#define AR_D_TXBLK_WRITE_BITMASK_S 0
+#define AR_D_TXBLK_WRITE_SLICE 0x000F0000
+#define AR_D_TXBLK_WRITE_SLICE_S 16
+#define AR_D_TXBLK_WRITE_DCU 0x00F00000
+#define AR_D_TXBLK_WRITE_DCU_S 20
+#define AR_D_TXBLK_WRITE_COMMAND 0x0F000000
+#define AR_D_TXBLK_WRITE_COMMAND_S 24
+
+#define AR_D_GBL_IFS_SLOT 0x1070
+#define AR_D_GBL_IFS_SLOT_M 0x0000FFFF
+#define AR_D_GBL_IFS_SLOT_RESV0 0xFFFF0000
+
+#define AR_D_GBL_IFS_EIFS 0x10b0
+#define AR_D_GBL_IFS_EIFS_M 0x0000FFFF
+#define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000
+
+#define AR_D_GBL_IFS_MISC 0x10f0
+#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007
+#define AR_D_GBL_IFS_MISC_TURBO_MODE 0x00000008
+#define AR_D_GBL_IFS_MISC_USEC_DURATION 0x000FFC00
+#define AR_D_GBL_IFS_MISC_DCU_ARBITER_DLY 0x00300000
+#define AR_D_GBL_IFS_MISC_RANDOM_LFSR_SLICE_DIS 0x01000000
+#define AR_D_GBL_IFS_MISC_SLOT_XMIT_WIND_LEN 0x06000000
+#define AR_D_GBL_IFS_MISC_FORCE_XMIT_SLOT_BOUND 0x08000000
+#define AR_D_GBL_IFS_MISC_IGNORE_BACKOFF 0x10000000
+
+#define AR_D_FPCTL 0x1230
+#define AR_D_FPCTL_DCU 0x0000000F
+#define AR_D_FPCTL_DCU_S 0
+#define AR_D_FPCTL_PREFETCH_EN 0x00000010
+#define AR_D_FPCTL_BURST_PREFETCH 0x00007FE0
+#define AR_D_FPCTL_BURST_PREFETCH_S 5
+
+#define AR_D_TXPSE 0x1270
+#define AR_D_TXPSE_CTRL 0x000003FF
+#define AR_D_TXPSE_RESV0 0x0000FC00
+#define AR_D_TXPSE_STATUS 0x00010000
+#define AR_D_TXPSE_RESV1 0xFFFE0000
+
+#define AR_D_TXSLOTMASK 0x12f0
+#define AR_D_TXSLOTMASK_NUM 0x0000000F
+
+#define AR_CFG_LED 0x1f04
+#define AR_CFG_SCLK_RATE_IND 0x00000003
+#define AR_CFG_SCLK_RATE_IND_S 0
+#define AR_CFG_SCLK_32MHZ 0x00000000
+#define AR_CFG_SCLK_4MHZ 0x00000001
+#define AR_CFG_SCLK_1MHZ 0x00000002
+#define AR_CFG_SCLK_32KHZ 0x00000003
+#define AR_CFG_LED_BLINK_SLOW 0x00000008
+#define AR_CFG_LED_BLINK_THRESH_SEL 0x00000070
+#define AR_CFG_LED_MODE_SEL 0x00000380
+#define AR_CFG_LED_MODE_SEL_S 7
+#define AR_CFG_LED_POWER 0x00000280
+#define AR_CFG_LED_POWER_S 7
+#define AR_CFG_LED_NETWORK 0x00000300
+#define AR_CFG_LED_NETWORK_S 7
+#define AR_CFG_LED_MODE_PROP 0x0
+#define AR_CFG_LED_MODE_RPROP 0x1
+#define AR_CFG_LED_MODE_SPLIT 0x2
+#define AR_CFG_LED_MODE_RAND 0x3
+#define AR_CFG_LED_MODE_POWER_OFF 0x4
+#define AR_CFG_LED_MODE_POWER_ON 0x5
+#define AR_CFG_LED_MODE_NETWORK_OFF 0x4
+#define AR_CFG_LED_MODE_NETWORK_ON 0x6
+#define AR_CFG_LED_ASSOC_CTL 0x00000c00
+#define AR_CFG_LED_ASSOC_CTL_S 10
+#define AR_CFG_LED_ASSOC_NONE 0x0
+#define AR_CFG_LED_ASSOC_ACTIVE 0x1
+#define AR_CFG_LED_ASSOC_PENDING 0x2
+
+#define AR_CFG_LED_BLINK_SLOW 0x00000008
+#define AR_CFG_LED_BLINK_SLOW_S 3
+
+#define AR_CFG_LED_BLINK_THRESH_SEL 0x00000070
+#define AR_CFG_LED_BLINK_THRESH_SEL_S 4
+
+#define AR_MAC_SLEEP 0x1f00
+#define AR_MAC_SLEEP_MAC_AWAKE 0x00000000
+#define AR_MAC_SLEEP_MAC_ASLEEP 0x00000001
+
+#define AR_RC 0x4000
+#define AR_RC_AHB 0x00000001
+#define AR_RC_APB 0x00000002
+#define AR_RC_HOSTIF 0x00000100
+
+#define AR_WA 0x4004
+
+#define AR_PM_STATE 0x4008
+#define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000
+
+#define AR_HOST_TIMEOUT 0x4018
+#define AR_HOST_TIMEOUT_APB_CNTR 0x0000FFFF
+#define AR_HOST_TIMEOUT_APB_CNTR_S 0
+#define AR_HOST_TIMEOUT_LCL_CNTR 0xFFFF0000
+#define AR_HOST_TIMEOUT_LCL_CNTR_S 16
+
+#define AR_EEPROM 0x401c
+#define AR_EEPROM_ABSENT 0x00000100
+#define AR_EEPROM_CORRUPT 0x00000200
+#define AR_EEPROM_PROT_MASK 0x03FFFC00
+#define AR_EEPROM_PROT_MASK_S 10
+
+#define EEPROM_PROTECT_RP_0_31 0x0001
+#define EEPROM_PROTECT_WP_0_31 0x0002
+#define EEPROM_PROTECT_RP_32_63 0x0004
+#define EEPROM_PROTECT_WP_32_63 0x0008
+#define EEPROM_PROTECT_RP_64_127 0x0010
+#define EEPROM_PROTECT_WP_64_127 0x0020
+#define EEPROM_PROTECT_RP_128_191 0x0040
+#define EEPROM_PROTECT_WP_128_191 0x0080
+#define EEPROM_PROTECT_RP_192_255 0x0100
+#define EEPROM_PROTECT_WP_192_255 0x0200
+#define EEPROM_PROTECT_RP_256_511 0x0400
+#define EEPROM_PROTECT_WP_256_511 0x0800
+#define EEPROM_PROTECT_RP_512_1023 0x1000
+#define EEPROM_PROTECT_WP_512_1023 0x2000
+#define EEPROM_PROTECT_RP_1024_2047 0x4000
+#define EEPROM_PROTECT_WP_1024_2047 0x8000
+
+#define AR_SREV \
+ ((AR_SREV_9100(ah)) ? 0x0600 : 0x4020)
+
+#define AR_SREV_ID \
+ ((AR_SREV_9100(ah)) ? 0x00000FFF : 0x000000FF)
+#define AR_SREV_VERSION 0x000000F0
+#define AR_SREV_VERSION_S 4
+#define AR_SREV_REVISION 0x00000007
+
+#define AR_SREV_ID2 0xFFFFFFFF
+#define AR_SREV_VERSION2 0xFFFC0000
+#define AR_SREV_VERSION2_S 18
+#define AR_SREV_TYPE2 0x0003F000
+#define AR_SREV_TYPE2_S 12
+#define AR_SREV_TYPE2_CHAIN 0x00001000
+#define AR_SREV_TYPE2_HOST_MODE 0x00002000
+#define AR_SREV_REVISION2 0x00000F00
+#define AR_SREV_REVISION2_S 8
+
+#define AR_SREV_VERSION_5416_PCI 0xD
+#define AR_SREV_VERSION_5416_PCIE 0xC
+#define AR_SREV_REVISION_5416_10 0
+#define AR_SREV_REVISION_5416_20 1
+#define AR_SREV_REVISION_5416_22 2
+#define AR_SREV_VERSION_9160 0x40
+#define AR_SREV_REVISION_9160_10 0
+#define AR_SREV_REVISION_9160_11 1
+#define AR_SREV_VERSION_9280 0x80
+#define AR_SREV_REVISION_9280_10 0
+#define AR_SREV_REVISION_9280_20 1
+#define AR_SREV_REVISION_9280_21 2
+#define AR_SREV_VERSION_9285 0xC0
+#define AR_SREV_REVISION_9285_10 0
+
+#define AR_SREV_9100_OR_LATER(_ah) \
+ (((_ah)->ah_macVersion >= AR_SREV_VERSION_5416_PCIE))
+#define AR_SREV_5416_20_OR_LATER(_ah) \
+ (((_ah)->ah_macVersion >= AR_SREV_VERSION_9160) || \
+ ((_ah)->ah_macRev >= AR_SREV_REVISION_5416_20))
+#define AR_SREV_5416_22_OR_LATER(_ah) \
+ (((_ah)->ah_macVersion >= AR_SREV_VERSION_9160) || \
+ ((_ah)->ah_macRev >= AR_SREV_REVISION_5416_22))
+#define AR_SREV_9160(_ah) \
+ (((_ah)->ah_macVersion == AR_SREV_VERSION_9160))
+#define AR_SREV_9160_10_OR_LATER(_ah) \
+ (((_ah)->ah_macVersion >= AR_SREV_VERSION_9160))
+#define AR_SREV_9160_11(_ah) \
+ (AR_SREV_9160(_ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9160_11))
+#define AR_SREV_9280(_ah) \
+ (((_ah)->ah_macVersion == AR_SREV_VERSION_9280))
+#define AR_SREV_9280_10_OR_LATER(_ah) \
+ (((_ah)->ah_macVersion >= AR_SREV_VERSION_9280))
+#define AR_SREV_9280_20(_ah) \
+ (((_ah)->ah_macVersion == AR_SREV_VERSION_9280) && \
+ ((_ah)->ah_macRev >= AR_SREV_REVISION_9280_20))
+#define AR_SREV_9280_20_OR_LATER(_ah) \
+ (((_ah)->ah_macVersion > AR_SREV_VERSION_9280) || \
+ (((_ah)->ah_macVersion == AR_SREV_VERSION_9280) && \
+ ((_ah)->ah_macRev >= AR_SREV_REVISION_9280_20)))
+
+#define AR_SREV_9285(_ah) (((_ah)->ah_macVersion == AR_SREV_VERSION_9285))
+#define AR_SREV_9285_10_OR_LATER(_ah) \
+ (((_ah)->ah_macVersion >= AR_SREV_VERSION_9285))
+
+#define AR_RADIO_SREV_MAJOR 0xf0
+#define AR_RAD5133_SREV_MAJOR 0xc0
+#define AR_RAD2133_SREV_MAJOR 0xd0
+#define AR_RAD5122_SREV_MAJOR 0xe0
+#define AR_RAD2122_SREV_MAJOR 0xf0
+
+#define AR_AHB_MODE 0x4024
+#define AR_AHB_EXACT_WR_EN 0x00000000
+#define AR_AHB_BUF_WR_EN 0x00000001
+#define AR_AHB_EXACT_RD_EN 0x00000000
+#define AR_AHB_CACHELINE_RD_EN 0x00000002
+#define AR_AHB_PREFETCH_RD_EN 0x00000004
+#define AR_AHB_PAGE_SIZE_1K 0x00000000
+#define AR_AHB_PAGE_SIZE_2K 0x00000008
+#define AR_AHB_PAGE_SIZE_4K 0x00000010
+
+#define AR_INTR_RTC_IRQ 0x00000001
+#define AR_INTR_MAC_IRQ 0x00000002
+#define AR_INTR_EEP_PROT_ACCESS 0x00000004
+#define AR_INTR_MAC_AWAKE 0x00020000
+#define AR_INTR_MAC_ASLEEP 0x00040000
+#define AR_INTR_SPURIOUS 0xFFFFFFFF
+
+
+#define AR_INTR_SYNC_CAUSE_CLR 0x4028
+
+#define AR_INTR_SYNC_CAUSE 0x4028
+
+#define AR_INTR_SYNC_ENABLE 0x402c
+#define AR_INTR_SYNC_ENABLE_GPIO 0xFFFC0000
+#define AR_INTR_SYNC_ENABLE_GPIO_S 18
+
+enum {
+ AR_INTR_SYNC_RTC_IRQ = 0x00000001,
+ AR_INTR_SYNC_MAC_IRQ = 0x00000002,
+ AR_INTR_SYNC_EEPROM_ILLEGAL_ACCESS = 0x00000004,
+ AR_INTR_SYNC_APB_TIMEOUT = 0x00000008,
+ AR_INTR_SYNC_PCI_MODE_CONFLICT = 0x00000010,
+ AR_INTR_SYNC_HOST1_FATAL = 0x00000020,
+ AR_INTR_SYNC_HOST1_PERR = 0x00000040,
+ AR_INTR_SYNC_TRCV_FIFO_PERR = 0x00000080,
+ AR_INTR_SYNC_RADM_CPL_EP = 0x00000100,
+ AR_INTR_SYNC_RADM_CPL_DLLP_ABORT = 0x00000200,
+ AR_INTR_SYNC_RADM_CPL_TLP_ABORT = 0x00000400,
+ AR_INTR_SYNC_RADM_CPL_ECRC_ERR = 0x00000800,
+ AR_INTR_SYNC_RADM_CPL_TIMEOUT = 0x00001000,
+ AR_INTR_SYNC_LOCAL_TIMEOUT = 0x00002000,
+ AR_INTR_SYNC_PM_ACCESS = 0x00004000,
+ AR_INTR_SYNC_MAC_AWAKE = 0x00008000,
+ AR_INTR_SYNC_MAC_ASLEEP = 0x00010000,
+ AR_INTR_SYNC_MAC_SLEEP_ACCESS = 0x00020000,
+ AR_INTR_SYNC_ALL = 0x0003FFFF,
+
+
+ AR_INTR_SYNC_DEFAULT = (AR_INTR_SYNC_HOST1_FATAL |
+ AR_INTR_SYNC_HOST1_PERR |
+ AR_INTR_SYNC_RADM_CPL_EP |
+ AR_INTR_SYNC_RADM_CPL_DLLP_ABORT |
+ AR_INTR_SYNC_RADM_CPL_TLP_ABORT |
+ AR_INTR_SYNC_RADM_CPL_ECRC_ERR |
+ AR_INTR_SYNC_RADM_CPL_TIMEOUT |
+ AR_INTR_SYNC_LOCAL_TIMEOUT |
+ AR_INTR_SYNC_MAC_SLEEP_ACCESS),
+
+ AR_INTR_SYNC_SPURIOUS = 0xFFFFFFFF,
+
+};
+
+#define AR_INTR_ASYNC_MASK 0x4030
+#define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000
+#define AR_INTR_ASYNC_MASK_GPIO_S 18
+
+#define AR_INTR_SYNC_MASK 0x4034
+#define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000
+#define AR_INTR_SYNC_MASK_GPIO_S 18
+
+#define AR_INTR_ASYNC_CAUSE_CLR 0x4038
+#define AR_INTR_ASYNC_CAUSE 0x4038
+
+#define AR_INTR_ASYNC_ENABLE 0x403c
+#define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000
+#define AR_INTR_ASYNC_ENABLE_GPIO_S 18
+
+#define AR_PCIE_SERDES 0x4040
+#define AR_PCIE_SERDES2 0x4044
+#define AR_PCIE_PM_CTRL 0x4014
+#define AR_PCIE_PM_CTRL_ENA 0x00080000
+
+#define AR_NUM_GPIO 14
+#define AR928X_NUM_GPIO 10
+
+#define AR_GPIO_IN_OUT 0x4048
+#define AR_GPIO_IN_VAL 0x0FFFC000
+#define AR_GPIO_IN_VAL_S 14
+#define AR928X_GPIO_IN_VAL 0x000FFC00
+#define AR928X_GPIO_IN_VAL_S 10
+
+#define AR_GPIO_OE_OUT 0x404c
+#define AR_GPIO_OE_OUT_DRV 0x3
+#define AR_GPIO_OE_OUT_DRV_NO 0x0
+#define AR_GPIO_OE_OUT_DRV_LOW 0x1
+#define AR_GPIO_OE_OUT_DRV_HI 0x2
+#define AR_GPIO_OE_OUT_DRV_ALL 0x3
+
+#define AR_GPIO_INTR_POL 0x4050
+#define AR_GPIO_INTR_POL_VAL 0x00001FFF
+#define AR_GPIO_INTR_POL_VAL_S 0
+
+#define AR_GPIO_INPUT_EN_VAL 0x4054
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF 0x00000080
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB 0x00008000
+#define AR_GPIO_INPUT_EN_VAL_RFSILENT_BB_S 15
+#define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000
+#define AR_GPIO_JTAG_DISABLE 0x00020000
+
+#define AR_GPIO_INPUT_MUX1 0x4058
+
+#define AR_GPIO_INPUT_MUX2 0x405c
+#define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f
+#define AR_GPIO_INPUT_MUX2_CLK25_S 0
+#define AR_GPIO_INPUT_MUX2_RFSILENT 0x000000f0
+#define AR_GPIO_INPUT_MUX2_RFSILENT_S 4
+#define AR_GPIO_INPUT_MUX2_RTC_RESET 0x00000f00
+#define AR_GPIO_INPUT_MUX2_RTC_RESET_S 8
+
+#define AR_GPIO_OUTPUT_MUX1 0x4060
+#define AR_GPIO_OUTPUT_MUX2 0x4064
+#define AR_GPIO_OUTPUT_MUX3 0x4068
+
+#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0
+#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
+#define AR_GPIO_OUTPUT_MUX_AS_PCIE_POWER_LED 2
+#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5
+#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6
+
+#define AR_INPUT_STATE 0x406c
+
+#define AR_EEPROM_STATUS_DATA 0x407c
+#define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff
+#define AR_EEPROM_STATUS_DATA_VAL_S 0
+#define AR_EEPROM_STATUS_DATA_BUSY 0x00010000
+#define AR_EEPROM_STATUS_DATA_BUSY_ACCESS 0x00020000
+#define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000
+#define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000
+
+#define AR_OBS 0x4080
+
+#define AR_PCIE_MSI 0x4094
+#define AR_PCIE_MSI_ENABLE 0x00000001
+
+
+#define AR_RTC_9160_PLL_DIV 0x000003ff
+#define AR_RTC_9160_PLL_DIV_S 0
+#define AR_RTC_9160_PLL_REFDIV 0x00003C00
+#define AR_RTC_9160_PLL_REFDIV_S 10
+#define AR_RTC_9160_PLL_CLKSEL 0x0000C000
+#define AR_RTC_9160_PLL_CLKSEL_S 14
+
+#define AR_RTC_BASE 0x00020000
+#define AR_RTC_RC \
+ (AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0000) : 0x7000
+#define AR_RTC_RC_M 0x00000003
+#define AR_RTC_RC_MAC_WARM 0x00000001
+#define AR_RTC_RC_MAC_COLD 0x00000002
+#define AR_RTC_RC_COLD_RESET 0x00000004
+#define AR_RTC_RC_WARM_RESET 0x00000008
+
+#define AR_RTC_PLL_CONTROL \
+ (AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0014) : 0x7014
+
+#define AR_RTC_PLL_DIV 0x0000001f
+#define AR_RTC_PLL_DIV_S 0
+#define AR_RTC_PLL_DIV2 0x00000020
+#define AR_RTC_PLL_REFDIV_5 0x000000c0
+#define AR_RTC_PLL_CLKSEL 0x00000300
+#define AR_RTC_PLL_CLKSEL_S 8
+
+
+
+#define AR_RTC_RESET \
+ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040)
+#define AR_RTC_RESET_EN (0x00000001)
+
+#define AR_RTC_STATUS \
+ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0044) : 0x7044)
+
+#define AR_RTC_STATUS_M \
+ ((AR_SREV_9100(ah)) ? 0x0000003f : 0x0000000f)
+
+#define AR_RTC_PM_STATUS_M 0x0000000f
+
+#define AR_RTC_STATUS_SHUTDOWN 0x00000001
+#define AR_RTC_STATUS_ON 0x00000002
+#define AR_RTC_STATUS_SLEEP 0x00000004
+#define AR_RTC_STATUS_WAKEUP 0x00000008
+
+#define AR_RTC_SLEEP_CLK \
+ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0048) : 0x7048)
+#define AR_RTC_FORCE_DERIVED_CLK 0x2
+
+#define AR_RTC_FORCE_WAKE \
+ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x004c) : 0x704c)
+#define AR_RTC_FORCE_WAKE_EN 0x00000001
+#define AR_RTC_FORCE_WAKE_ON_INT 0x00000002
+
+
+#define AR_RTC_INTR_CAUSE \
+ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0050) : 0x7050)
+
+#define AR_RTC_INTR_ENABLE \
+ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0054) : 0x7054)
+
+#define AR_RTC_INTR_MASK \
+ ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058)
+
+#define AR_SEQ_MASK 0x8060
+
+#define AR_AN_RF2G1_CH0 0x7810
+#define AR_AN_RF2G1_CH0_OB 0x03800000
+#define AR_AN_RF2G1_CH0_OB_S 23
+#define AR_AN_RF2G1_CH0_DB 0x1C000000
+#define AR_AN_RF2G1_CH0_DB_S 26
+
+#define AR_AN_RF5G1_CH0 0x7818
+#define AR_AN_RF5G1_CH0_OB5 0x00070000
+#define AR_AN_RF5G1_CH0_OB5_S 16
+#define AR_AN_RF5G1_CH0_DB5 0x00380000
+#define AR_AN_RF5G1_CH0_DB5_S 19
+
+#define AR_AN_RF2G1_CH1 0x7834
+#define AR_AN_RF2G1_CH1_OB 0x03800000
+#define AR_AN_RF2G1_CH1_OB_S 23
+#define AR_AN_RF2G1_CH1_DB 0x1C000000
+#define AR_AN_RF2G1_CH1_DB_S 26
+
+#define AR_AN_RF5G1_CH1 0x783C
+#define AR_AN_RF5G1_CH1_OB5 0x00070000
+#define AR_AN_RF5G1_CH1_OB5_S 16
+#define AR_AN_RF5G1_CH1_DB5 0x00380000
+#define AR_AN_RF5G1_CH1_DB5_S 19
+
+#define AR_AN_TOP2 0x7894
+#define AR_AN_TOP2_XPABIAS_LVL 0xC0000000
+#define AR_AN_TOP2_XPABIAS_LVL_S 30
+#define AR_AN_TOP2_LOCALBIAS 0x00200000
+#define AR_AN_TOP2_LOCALBIAS_S 21
+#define AR_AN_TOP2_PWDCLKIND 0x00400000
+#define AR_AN_TOP2_PWDCLKIND_S 22
+
+#define AR_AN_SYNTH9 0x7868
+#define AR_AN_SYNTH9_REFDIVA 0xf8000000
+#define AR_AN_SYNTH9_REFDIVA_S 27
+
+#define AR_STA_ID0 0x8000
+#define AR_STA_ID1 0x8004
+#define AR_STA_ID1_SADH_MASK 0x0000FFFF
+#define AR_STA_ID1_STA_AP 0x00010000
+#define AR_STA_ID1_ADHOC 0x00020000
+#define AR_STA_ID1_PWR_SAV 0x00040000
+#define AR_STA_ID1_KSRCHDIS 0x00080000
+#define AR_STA_ID1_PCF 0x00100000
+#define AR_STA_ID1_USE_DEFANT 0x00200000
+#define AR_STA_ID1_DEFANT_UPDATE 0x00400000
+#define AR_STA_ID1_RTS_USE_DEF 0x00800000
+#define AR_STA_ID1_ACKCTS_6MB 0x01000000
+#define AR_STA_ID1_BASE_RATE_11B 0x02000000
+#define AR_STA_ID1_SECTOR_SELF_GEN 0x04000000
+#define AR_STA_ID1_CRPT_MIC_ENABLE 0x08000000
+#define AR_STA_ID1_KSRCH_MODE 0x10000000
+#define AR_STA_ID1_PRESERVE_SEQNUM 0x20000000
+#define AR_STA_ID1_CBCIV_ENDIAN 0x40000000
+#define AR_STA_ID1_MCAST_KSRCH 0x80000000
+
+#define AR_BSS_ID0 0x8008
+#define AR_BSS_ID1 0x800C
+#define AR_BSS_ID1_U16 0x0000FFFF
+#define AR_BSS_ID1_AID 0x07FF0000
+#define AR_BSS_ID1_AID_S 16
+
+#define AR_BCN_RSSI_AVE 0x8010
+#define AR_BCN_RSSI_AVE_MASK 0x00000FFF
+
+#define AR_TIME_OUT 0x8014
+#define AR_TIME_OUT_ACK 0x00003FFF
+#define AR_TIME_OUT_ACK_S 0
+#define AR_TIME_OUT_CTS 0x3FFF0000
+#define AR_TIME_OUT_CTS_S 16
+
+#define AR_RSSI_THR 0x8018
+#define AR_RSSI_THR_MASK 0x000000FF
+#define AR_RSSI_THR_BM_THR 0x0000FF00
+#define AR_RSSI_THR_BM_THR_S 8
+#define AR_RSSI_BCN_WEIGHT 0x1F000000
+#define AR_RSSI_BCN_WEIGHT_S 24
+#define AR_RSSI_BCN_RSSI_RST 0x20000000
+
+#define AR_USEC 0x801c
+#define AR_USEC_USEC 0x0000007F
+#define AR_USEC_TX_LAT 0x007FC000
+#define AR_USEC_TX_LAT_S 14
+#define AR_USEC_RX_LAT 0x1F800000
+#define AR_USEC_RX_LAT_S 23
+
+#define AR_RESET_TSF 0x8020
+#define AR_RESET_TSF_ONCE 0x01000000
+
+#define AR_MAX_CFP_DUR 0x8038
+#define AR_CFP_VAL 0x0000FFFF
+
+#define AR_RX_FILTER 0x803C
+#define AR_RX_FILTER_ALL 0x00000000
+#define AR_RX_UCAST 0x00000001
+#define AR_RX_MCAST 0x00000002
+#define AR_RX_BCAST 0x00000004
+#define AR_RX_CONTROL 0x00000008
+#define AR_RX_BEACON 0x00000010
+#define AR_RX_PROM 0x00000020
+#define AR_RX_PROBE_REQ 0x00000080
+#define AR_RX_MY_BEACON 0x00000200
+#define AR_RX_COMPR_BAR 0x00000400
+#define AR_RX_COMPR_BA 0x00000800
+#define AR_RX_UNCOM_BA_BAR 0x00001000
+
+#define AR_MCAST_FIL0 0x8040
+#define AR_MCAST_FIL1 0x8044
+
+#define AR_DIAG_SW 0x8048
+#define AR_DIAG_CACHE_ACK 0x00000001
+#define AR_DIAG_ACK_DIS 0x00000002
+#define AR_DIAG_CTS_DIS 0x00000004
+#define AR_DIAG_ENCRYPT_DIS 0x00000008
+#define AR_DIAG_DECRYPT_DIS 0x00000010
+#define AR_DIAG_RX_DIS 0x00000020
+#define AR_DIAG_LOOP_BACK 0x00000040
+#define AR_DIAG_CORR_FCS 0x00000080
+#define AR_DIAG_CHAN_INFO 0x00000100
+#define AR_DIAG_SCRAM_SEED 0x0001FE00
+#define AR_DIAG_SCRAM_SEED_S 8
+#define AR_DIAG_FRAME_NV0 0x00020000
+#define AR_DIAG_OBS_PT_SEL1 0x000C0000
+#define AR_DIAG_OBS_PT_SEL1_S 18
+#define AR_DIAG_FORCE_RX_CLEAR 0x00100000
+#define AR_DIAG_IGNORE_VIRT_CS 0x00200000
+#define AR_DIAG_FORCE_CH_IDLE_HIGH 0x00400000
+#define AR_DIAG_EIFS_CTRL_ENA 0x00800000
+#define AR_DIAG_DUAL_CHAIN_INFO 0x01000000
+#define AR_DIAG_RX_ABORT 0x02000000
+#define AR_DIAG_SATURATE_CYCLE_CNT 0x04000000
+#define AR_DIAG_OBS_PT_SEL2 0x08000000
+#define AR_DIAG_RX_CLEAR_CTL_LOW 0x10000000
+#define AR_DIAG_RX_CLEAR_EXT_LOW 0x20000000
+
+#define AR_TSF_L32 0x804c
+#define AR_TSF_U32 0x8050
+
+#define AR_TST_ADDAC 0x8054
+#define AR_DEF_ANTENNA 0x8058
+
+#define AR_AES_MUTE_MASK0 0x805c
+#define AR_AES_MUTE_MASK0_FC 0x0000FFFF
+#define AR_AES_MUTE_MASK0_QOS 0xFFFF0000
+#define AR_AES_MUTE_MASK0_QOS_S 16
+
+#define AR_AES_MUTE_MASK1 0x8060
+#define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF
+
+#define AR_GATED_CLKS 0x8064
+#define AR_GATED_CLKS_TX 0x00000002
+#define AR_GATED_CLKS_RX 0x00000004
+#define AR_GATED_CLKS_REG 0x00000008
+
+#define AR_OBS_BUS_CTRL 0x8068
+#define AR_OBS_BUS_SEL_1 0x00040000
+#define AR_OBS_BUS_SEL_2 0x00080000
+#define AR_OBS_BUS_SEL_3 0x000C0000
+#define AR_OBS_BUS_SEL_4 0x08040000
+#define AR_OBS_BUS_SEL_5 0x08080000
+
+#define AR_OBS_BUS_1 0x806c
+#define AR_OBS_BUS_1_PCU 0x00000001
+#define AR_OBS_BUS_1_RX_END 0x00000002
+#define AR_OBS_BUS_1_RX_WEP 0x00000004
+#define AR_OBS_BUS_1_RX_BEACON 0x00000008
+#define AR_OBS_BUS_1_RX_FILTER 0x00000010
+#define AR_OBS_BUS_1_TX_HCF 0x00000020
+#define AR_OBS_BUS_1_QUIET_TIME 0x00000040
+#define AR_OBS_BUS_1_CHAN_IDLE 0x00000080
+#define AR_OBS_BUS_1_TX_HOLD 0x00000100
+#define AR_OBS_BUS_1_TX_FRAME 0x00000200
+#define AR_OBS_BUS_1_RX_FRAME 0x00000400
+#define AR_OBS_BUS_1_RX_CLEAR 0x00000800
+#define AR_OBS_BUS_1_WEP_STATE 0x0003F000
+#define AR_OBS_BUS_1_WEP_STATE_S 12
+#define AR_OBS_BUS_1_RX_STATE 0x01F00000
+#define AR_OBS_BUS_1_RX_STATE_S 20
+#define AR_OBS_BUS_1_TX_STATE 0x7E000000
+#define AR_OBS_BUS_1_TX_STATE_S 25
+
+#define AR_LAST_TSTP 0x8080
+#define AR_NAV 0x8084
+#define AR_RTS_OK 0x8088
+#define AR_RTS_FAIL 0x808c
+#define AR_ACK_FAIL 0x8090
+#define AR_FCS_FAIL 0x8094
+#define AR_BEACON_CNT 0x8098
+
+#define AR_SLEEP1 0x80d4
+#define AR_SLEEP1_ASSUME_DTIM 0x00080000
+#define AR_SLEEP1_CAB_TIMEOUT 0xFFE00000
+#define AR_SLEEP1_CAB_TIMEOUT_S 21
+
+#define AR_SLEEP2 0x80d8
+#define AR_SLEEP2_BEACON_TIMEOUT 0xFFE00000
+#define AR_SLEEP2_BEACON_TIMEOUT_S 21
+
+#define AR_BSSMSKL 0x80e0
+#define AR_BSSMSKU 0x80e4
+
+#define AR_TPC 0x80e8
+#define AR_TPC_ACK 0x0000003f
+#define AR_TPC_ACK_S 0x00
+#define AR_TPC_CTS 0x00003f00
+#define AR_TPC_CTS_S 0x08
+#define AR_TPC_CHIRP 0x003f0000
+#define AR_TPC_CHIRP_S 0x16
+
+#define AR_TFCNT 0x80ec
+#define AR_RFCNT 0x80f0
+#define AR_RCCNT 0x80f4
+#define AR_CCCNT 0x80f8
+
+#define AR_QUIET1 0x80fc
+#define AR_QUIET1_NEXT_QUIET_S 0
+#define AR_QUIET1_NEXT_QUIET_M 0x0000ffff
+#define AR_QUIET1_QUIET_ENABLE 0x00010000
+#define AR_QUIET1_QUIET_ACK_CTS_ENABLE 0x00020000
+#define AR_QUIET2 0x8100
+#define AR_QUIET2_QUIET_PERIOD_S 0
+#define AR_QUIET2_QUIET_PERIOD_M 0x0000ffff
+#define AR_QUIET2_QUIET_DUR_S 16
+#define AR_QUIET2_QUIET_DUR 0xffff0000
+
+#define AR_TSF_PARM 0x8104
+#define AR_TSF_INCREMENT_M 0x000000ff
+#define AR_TSF_INCREMENT_S 0x00
+
+#define AR_QOS_NO_ACK 0x8108
+#define AR_QOS_NO_ACK_TWO_BIT 0x0000000f
+#define AR_QOS_NO_ACK_TWO_BIT_S 0
+#define AR_QOS_NO_ACK_BIT_OFF 0x00000070
+#define AR_QOS_NO_ACK_BIT_OFF_S 4
+#define AR_QOS_NO_ACK_BYTE_OFF 0x00000180
+#define AR_QOS_NO_ACK_BYTE_OFF_S 7
+
+#define AR_PHY_ERR 0x810c
+
+#define AR_PHY_ERR_DCHIRP 0x00000008
+#define AR_PHY_ERR_RADAR 0x00000020
+#define AR_PHY_ERR_OFDM_TIMING 0x00020000
+#define AR_PHY_ERR_CCK_TIMING 0x02000000
+
+#define AR_RXFIFO_CFG 0x8114
+
+
+#define AR_MIC_QOS_CONTROL 0x8118
+#define AR_MIC_QOS_SELECT 0x811c
+
+#define AR_PCU_MISC 0x8120
+#define AR_PCU_FORCE_BSSID_MATCH 0x00000001
+#define AR_PCU_MIC_NEW_LOC_ENA 0x00000004
+#define AR_PCU_TX_ADD_TSF 0x00000008
+#define AR_PCU_CCK_SIFS_MODE 0x00000010
+#define AR_PCU_RX_ANT_UPDT 0x00000800
+#define AR_PCU_TXOP_TBTT_LIMIT_ENA 0x00001000
+#define AR_PCU_MISS_BCN_IN_SLEEP 0x00004000
+#define AR_PCU_BUG_12306_FIX_ENA 0x00020000
+#define AR_PCU_FORCE_QUIET_COLL 0x00040000
+#define AR_PCU_TBTT_PROTECT 0x00200000
+#define AR_PCU_CLEAR_VMF 0x01000000
+#define AR_PCU_CLEAR_BA_VALID 0x04000000
+
+
+#define AR_FILT_OFDM 0x8124
+#define AR_FILT_OFDM_COUNT 0x00FFFFFF
+
+#define AR_FILT_CCK 0x8128
+#define AR_FILT_CCK_COUNT 0x00FFFFFF
+
+#define AR_PHY_ERR_1 0x812c
+#define AR_PHY_ERR_1_COUNT 0x00FFFFFF
+#define AR_PHY_ERR_MASK_1 0x8130
+
+#define AR_PHY_ERR_2 0x8134
+#define AR_PHY_ERR_2_COUNT 0x00FFFFFF
+#define AR_PHY_ERR_MASK_2 0x8138
+
+#define AR_PHY_COUNTMAX (3 << 22)
+#define AR_MIBCNT_INTRMASK (3 << 22)
+
+#define AR_TSF_THRESHOLD 0x813c
+#define AR_TSF_THRESHOLD_VAL 0x0000FFFF
+
+#define AR_PHY_ERR_EIFS_MASK 8144
+
+#define AR_PHY_ERR_3 0x8168
+#define AR_PHY_ERR_3_COUNT 0x00FFFFFF
+#define AR_PHY_ERR_MASK_3 0x816c
+
+#define AR_TXSIFS 0x81d0
+#define AR_TXSIFS_TIME 0x000000FF
+#define AR_TXSIFS_TX_LATENCY 0x00000F00
+#define AR_TXSIFS_TX_LATENCY_S 8
+#define AR_TXSIFS_ACK_SHIFT 0x00007000
+#define AR_TXSIFS_ACK_SHIFT_S 12
+
+#define AR_TXOP_X 0x81ec
+#define AR_TXOP_X_VAL 0x000000FF
+
+
+#define AR_TXOP_0_3 0x81f0
+#define AR_TXOP_4_7 0x81f4
+#define AR_TXOP_8_11 0x81f8
+#define AR_TXOP_12_15 0x81fc
+
+
+#define AR_NEXT_TBTT_TIMER 0x8200
+#define AR_NEXT_DMA_BEACON_ALERT 0x8204
+#define AR_NEXT_SWBA 0x8208
+#define AR_NEXT_CFP 0x8208
+#define AR_NEXT_HCF 0x820C
+#define AR_NEXT_TIM 0x8210
+#define AR_NEXT_DTIM 0x8214
+#define AR_NEXT_QUIET_TIMER 0x8218
+#define AR_NEXT_NDP_TIMER 0x821C
+
+#define AR_BEACON_PERIOD 0x8220
+#define AR_DMA_BEACON_PERIOD 0x8224
+#define AR_SWBA_PERIOD 0x8228
+#define AR_HCF_PERIOD 0x822C
+#define AR_TIM_PERIOD 0x8230
+#define AR_DTIM_PERIOD 0x8234
+#define AR_QUIET_PERIOD 0x8238
+#define AR_NDP_PERIOD 0x823C
+
+#define AR_TIMER_MODE 0x8240
+#define AR_TBTT_TIMER_EN 0x00000001
+#define AR_DBA_TIMER_EN 0x00000002
+#define AR_SWBA_TIMER_EN 0x00000004
+#define AR_HCF_TIMER_EN 0x00000008
+#define AR_TIM_TIMER_EN 0x00000010
+#define AR_DTIM_TIMER_EN 0x00000020
+#define AR_QUIET_TIMER_EN 0x00000040
+#define AR_NDP_TIMER_EN 0x00000080
+#define AR_TIMER_OVERFLOW_INDEX 0x00000700
+#define AR_TIMER_OVERFLOW_INDEX_S 8
+#define AR_TIMER_THRESH 0xFFFFF000
+#define AR_TIMER_THRESH_S 12
+
+#define AR_SLP32_MODE 0x8244
+#define AR_SLP32_HALF_CLK_LATENCY 0x000FFFFF
+#define AR_SLP32_ENA 0x00100000
+#define AR_SLP32_TSF_WRITE_STATUS 0x00200000
+
+#define AR_SLP32_WAKE 0x8248
+#define AR_SLP32_WAKE_XTL_TIME 0x0000FFFF
+
+#define AR_SLP32_INC 0x824c
+#define AR_SLP32_TST_INC 0x000FFFFF
+
+#define AR_SLP_CNT 0x8250
+#define AR_SLP_CYCLE_CNT 0x8254
+
+#define AR_SLP_MIB_CTRL 0x8258
+#define AR_SLP_MIB_CLEAR 0x00000001
+#define AR_SLP_MIB_PENDING 0x00000002
+
+#define AR_2040_MODE 0x8318
+#define AR_2040_JOINED_RX_CLEAR 0x00000001
+
+
+#define AR_EXTRCCNT 0x8328
+
+#define AR_SELFGEN_MASK 0x832c
+
+#define AR_PCU_TXBUF_CTRL 0x8340
+#define AR_PCU_TXBUF_CTRL_SIZE_MASK 0x7FF
+#define AR_PCU_TXBUF_CTRL_USABLE_SIZE 0x700
+#define AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE 0x380
+
+#define AR_KEYTABLE_0 0x8800
+#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32))
+#define AR_KEY_CACHE_SIZE 128
+#define AR_RSVD_KEYTABLE_ENTRIES 4
+#define AR_KEY_TYPE 0x00000007
+#define AR_KEYTABLE_TYPE_40 0x00000000
+#define AR_KEYTABLE_TYPE_104 0x00000001
+#define AR_KEYTABLE_TYPE_128 0x00000003
+#define AR_KEYTABLE_TYPE_TKIP 0x00000004
+#define AR_KEYTABLE_TYPE_AES 0x00000005
+#define AR_KEYTABLE_TYPE_CCM 0x00000006
+#define AR_KEYTABLE_TYPE_CLR 0x00000007
+#define AR_KEYTABLE_ANT 0x00000008
+#define AR_KEYTABLE_VALID 0x00008000
+#define AR_KEYTABLE_KEY0(_n) (AR_KEYTABLE(_n) + 0)
+#define AR_KEYTABLE_KEY1(_n) (AR_KEYTABLE(_n) + 4)
+#define AR_KEYTABLE_KEY2(_n) (AR_KEYTABLE(_n) + 8)
+#define AR_KEYTABLE_KEY3(_n) (AR_KEYTABLE(_n) + 12)
+#define AR_KEYTABLE_KEY4(_n) (AR_KEYTABLE(_n) + 16)
+#define AR_KEYTABLE_TYPE(_n) (AR_KEYTABLE(_n) + 20)
+#define AR_KEYTABLE_MAC0(_n) (AR_KEYTABLE(_n) + 24)
+#define AR_KEYTABLE_MAC1(_n) (AR_KEYTABLE(_n) + 28)
+
+#endif
diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c
new file mode 100644
index 00000000000..62e28887ccd
--- /dev/null
+++ b/drivers/net/wireless/ath9k/regd.c
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "core.h"
+#include "hw.h"
+#include "regd.h"
+#include "regd_common.h"
+
+static int ath9k_regd_chansort(const void *a, const void *b)
+{
+ const struct ath9k_channel *ca = a;
+ const struct ath9k_channel *cb = b;
+
+ return (ca->channel == cb->channel) ?
+ (ca->channelFlags & CHAN_FLAGS) -
+ (cb->channelFlags & CHAN_FLAGS) : ca->channel - cb->channel;
+}
+
+static void
+ath9k_regd_sort(void *a, u32 n, u32 size, ath_hal_cmp_t *cmp)
+{
+ u8 *aa = a;
+ u8 *ai, *t;
+
+ for (ai = aa + size; --n >= 1; ai += size)
+ for (t = ai; t > aa; t -= size) {
+ u8 *u = t - size;
+ if (cmp(u, t) <= 0)
+ break;
+ swap(u, t, size);
+ }
+}
+
+static u16 ath9k_regd_get_eepromRD(struct ath_hal *ah)
+{
+ return ah->ah_currentRD & ~WORLDWIDE_ROAMING_FLAG;
+}
+
+static bool ath9k_regd_is_chan_bm_zero(u64 *bitmask)
+{
+ int i;
+
+ for (i = 0; i < BMLEN; i++) {
+ if (bitmask[i] != 0)
+ return false;
+ }
+ return true;
+}
+
+static bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah)
+{
+ u16 rd = ath9k_regd_get_eepromRD(ah);
+ int i;
+
+ if (rd & COUNTRY_ERD_FLAG) {
+ u16 cc = rd & ~COUNTRY_ERD_FLAG;
+ for (i = 0; i < ARRAY_SIZE(allCountries); i++)
+ if (allCountries[i].countryCode == cc)
+ return true;
+ } else {
+ for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
+ if (regDomainPairs[i].regDmnEnum == rd)
+ return true;
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: invalid regulatory domain/country code 0x%x\n",
+ __func__, rd);
+ return false;
+}
+
+static bool ath9k_regd_is_fcc_midband_supported(struct ath_hal *ah)
+{
+ u32 regcap;
+
+ regcap = ah->ah_caps.reg_cap;
+
+ if (regcap & AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND)
+ return true;
+ else
+ return false;
+}
+
+static bool ath9k_regd_is_ccode_valid(struct ath_hal *ah,
+ u16 cc)
+{
+ u16 rd;
+ int i;
+
+ if (cc == CTRY_DEFAULT)
+ return true;
+ if (cc == CTRY_DEBUG)
+ return true;
+
+ rd = ath9k_regd_get_eepromRD(ah);
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: EEPROM regdomain 0x%x\n",
+ __func__, rd);
+
+ if (rd & COUNTRY_ERD_FLAG) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: EEPROM setting is country code %u\n",
+ __func__, rd & ~COUNTRY_ERD_FLAG);
+ return cc == (rd & ~COUNTRY_ERD_FLAG);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
+ if (cc == allCountries[i].countryCode) {
+#ifdef AH_SUPPORT_11D
+ if ((rd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)
+ return true;
+#endif
+ if (allCountries[i].regDmnEnum == rd ||
+ rd == DEBUG_REG_DMN || rd == NO_ENUMRD)
+ return true;
+ }
+ }
+ return false;
+}
+
+static void
+ath9k_regd_get_wmodes_nreg(struct ath_hal *ah,
+ struct country_code_to_enum_rd *country,
+ struct regDomain *rd5GHz,
+ unsigned long *modes_allowed)
+{
+ bitmap_copy(modes_allowed, ah->ah_caps.wireless_modes, ATH9K_MODE_MAX);
+
+ if (test_bit(ATH9K_MODE_11G, ah->ah_caps.wireless_modes) &&
+ (!country->allow11g))
+ clear_bit(ATH9K_MODE_11G, modes_allowed);
+
+ if (test_bit(ATH9K_MODE_11A, ah->ah_caps.wireless_modes) &&
+ (ath9k_regd_is_chan_bm_zero(rd5GHz->chan11a)))
+ clear_bit(ATH9K_MODE_11A, modes_allowed);
+
+ if (test_bit(ATH9K_MODE_11NG_HT20, ah->ah_caps.wireless_modes)
+ && (!country->allow11ng20))
+ clear_bit(ATH9K_MODE_11NG_HT20, modes_allowed);
+
+ if (test_bit(ATH9K_MODE_11NA_HT20, ah->ah_caps.wireless_modes)
+ && (!country->allow11na20))
+ clear_bit(ATH9K_MODE_11NA_HT20, modes_allowed);
+
+ if (test_bit(ATH9K_MODE_11NG_HT40PLUS, ah->ah_caps.wireless_modes) &&
+ (!country->allow11ng40))
+ clear_bit(ATH9K_MODE_11NG_HT40PLUS, modes_allowed);
+
+ if (test_bit(ATH9K_MODE_11NG_HT40MINUS, ah->ah_caps.wireless_modes) &&
+ (!country->allow11ng40))
+ clear_bit(ATH9K_MODE_11NG_HT40MINUS, modes_allowed);
+
+ if (test_bit(ATH9K_MODE_11NA_HT40PLUS, ah->ah_caps.wireless_modes) &&
+ (!country->allow11na40))
+ clear_bit(ATH9K_MODE_11NA_HT40PLUS, modes_allowed);
+
+ if (test_bit(ATH9K_MODE_11NA_HT40MINUS, ah->ah_caps.wireless_modes) &&
+ (!country->allow11na40))
+ clear_bit(ATH9K_MODE_11NA_HT40MINUS, modes_allowed);
+}
+
+bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah)
+{
+ u16 rd;
+
+ rd = ath9k_regd_get_eepromRD(ah);
+
+ switch (rd) {
+ case FCC4_FCCA:
+ case (CTRY_UNITED_STATES_FCC49 | COUNTRY_ERD_FLAG):
+ return true;
+ case DEBUG_REG_DMN:
+ case NO_ENUMRD:
+ if (ah->ah_countryCode == CTRY_UNITED_STATES_FCC49)
+ return true;
+ break;
+ }
+ return false;
+}
+
+static struct country_code_to_enum_rd*
+ath9k_regd_find_country(u16 countryCode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(allCountries); i++) {
+ if (allCountries[i].countryCode == countryCode)
+ return &allCountries[i];
+ }
+ return NULL;
+}
+
+static u16 ath9k_regd_get_default_country(struct ath_hal *ah)
+{
+ u16 rd;
+ int i;
+
+ rd = ath9k_regd_get_eepromRD(ah);
+ if (rd & COUNTRY_ERD_FLAG) {
+ struct country_code_to_enum_rd *country = NULL;
+ u16 cc = rd & ~COUNTRY_ERD_FLAG;
+
+ country = ath9k_regd_find_country(cc);
+ if (country != NULL)
+ return cc;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
+ if (regDomainPairs[i].regDmnEnum == rd) {
+ if (regDomainPairs[i].singleCC != 0)
+ return regDomainPairs[i].singleCC;
+ else
+ i = ARRAY_SIZE(regDomainPairs);
+ }
+ return CTRY_DEFAULT;
+}
+
+static bool ath9k_regd_is_valid_reg_domain(int regDmn,
+ struct regDomain *rd)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(regDomains); i++) {
+ if (regDomains[i].regDmnEnum == regDmn) {
+ if (rd != NULL) {
+ memcpy(rd, &regDomains[i],
+ sizeof(struct regDomain));
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool ath9k_regd_is_valid_reg_domainPair(int regDmnPair)
+{
+ int i;
+
+ if (regDmnPair == NO_ENUMRD)
+ return false;
+ for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) {
+ if (regDomainPairs[i].regDmnEnum == regDmnPair)
+ return true;
+ }
+ return false;
+}
+
+static bool
+ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn,
+ u16 channelFlag, struct regDomain *rd)
+{
+ int i, found;
+ u64 flags = NO_REQ;
+ struct reg_dmn_pair_mapping *regPair = NULL;
+ int regOrg;
+
+ regOrg = regDmn;
+ if (regDmn == CTRY_DEFAULT) {
+ u16 rdnum;
+ rdnum = ath9k_regd_get_eepromRD(ah);
+
+ if (!(rdnum & COUNTRY_ERD_FLAG)) {
+ if (ath9k_regd_is_valid_reg_domain(rdnum, NULL) ||
+ ath9k_regd_is_valid_reg_domainPair(rdnum)) {
+ regDmn = rdnum;
+ }
+ }
+ }
+
+ if ((regDmn & MULTI_DOMAIN_MASK) == 0) {
+ for (i = 0, found = 0;
+ (i < ARRAY_SIZE(regDomainPairs)) && (!found); i++) {
+ if (regDomainPairs[i].regDmnEnum == regDmn) {
+ regPair = &regDomainPairs[i];
+ found = 1;
+ }
+ }
+ if (!found) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: Failed to find reg domain pair %u\n",
+ __func__, regDmn);
+ return false;
+ }
+ if (!(channelFlag & CHANNEL_2GHZ)) {
+ regDmn = regPair->regDmn5GHz;
+ flags = regPair->flags5GHz;
+ }
+ if (channelFlag & CHANNEL_2GHZ) {
+ regDmn = regPair->regDmn2GHz;
+ flags = regPair->flags2GHz;
+ }
+ }
+
+ found = ath9k_regd_is_valid_reg_domain(regDmn, rd);
+ if (!found) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: Failed to find unitary reg domain %u\n",
+ __func__, regDmn);
+ return false;
+ } else {
+ rd->pscan &= regPair->pscanMask;
+ if (((regOrg & MULTI_DOMAIN_MASK) == 0) &&
+ (flags != NO_REQ)) {
+ rd->flags = flags;
+ }
+
+ rd->flags &= (channelFlag & CHANNEL_2GHZ) ?
+ REG_DOMAIN_2GHZ_MASK : REG_DOMAIN_5GHZ_MASK;
+ return true;
+ }
+}
+
+static bool ath9k_regd_is_bit_set(int bit, u64 *bitmask)
+{
+ int byteOffset, bitnum;
+ u64 val;
+
+ byteOffset = bit / 64;
+ bitnum = bit - byteOffset * 64;
+ val = ((u64) 1) << bitnum;
+ if (bitmask[byteOffset] & val)
+ return true;
+ else
+ return false;
+}
+
+static void
+ath9k_regd_add_reg_classid(u8 *regclassids, u32 maxregids,
+ u32 *nregids, u8 regclassid)
+{
+ int i;
+
+ if (regclassid == 0)
+ return;
+
+ for (i = 0; i < maxregids; i++) {
+ if (regclassids[i] == regclassid)
+ return;
+ if (regclassids[i] == 0)
+ break;
+ }
+
+ if (i == maxregids)
+ return;
+ else {
+ regclassids[i] = regclassid;
+ *nregids += 1;
+ }
+
+ return;
+}
+
+static bool
+ath9k_regd_get_eeprom_reg_ext_bits(struct ath_hal *ah,
+ enum reg_ext_bitmap bit)
+{
+ return (ah->ah_currentRDExt & (1 << bit)) ? true : false;
+}
+
+#ifdef ATH_NF_PER_CHAN
+
+static void ath9k_regd_init_rf_buffer(struct ath9k_channel *ichans,
+ int nchans)
+{
+ int i, j, next;
+
+ for (next = 0; next < nchans; next++) {
+ for (i = 0; i < NUM_NF_READINGS; i++) {
+ ichans[next].nfCalHist[i].currIndex = 0;
+ ichans[next].nfCalHist[i].privNF =
+ AR_PHY_CCA_MAX_GOOD_VALUE;
+ ichans[next].nfCalHist[i].invalidNFcount =
+ AR_PHY_CCA_FILTERWINDOW_LENGTH;
+ for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
+ ichans[next].nfCalHist[i].nfCalBuffer[j] =
+ AR_PHY_CCA_MAX_GOOD_VALUE;
+ }
+ }
+ }
+}
+#endif
+
+static int ath9k_regd_is_chan_present(struct ath_hal *ah,
+ u16 c)
+{
+ int i;
+
+ for (i = 0; i < 150; i++) {
+ if (!ah->ah_channels[i].channel)
+ return -1;
+ else if (ah->ah_channels[i].channel == c)
+ return i;
+ }
+
+ return -1;
+}
+
+static bool
+ath9k_regd_add_channel(struct ath_hal *ah,
+ u16 c,
+ u16 c_lo,
+ u16 c_hi,
+ u16 maxChan,
+ u8 ctl,
+ int pos,
+ struct regDomain rd5GHz,
+ struct RegDmnFreqBand *fband,
+ struct regDomain *rd,
+ const struct cmode *cm,
+ struct ath9k_channel *ichans,
+ bool enableExtendedChannels)
+{
+ struct ath9k_channel *chan;
+ int ret;
+ u32 channelFlags = 0;
+ u8 privFlags = 0;
+
+ if (!(c_lo <= c && c <= c_hi)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: c %u out of range [%u..%u]\n",
+ __func__, c, c_lo, c_hi);
+ return false;
+ }
+ if ((fband->channelBW == CHANNEL_HALF_BW) &&
+ !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_HALFRATE)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: Skipping %u half rate channel\n",
+ __func__, c);
+ return false;
+ }
+
+ if ((fband->channelBW == CHANNEL_QUARTER_BW) &&
+ !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_QUARTERRATE)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: Skipping %u quarter rate channel\n",
+ __func__, c);
+ return false;
+ }
+
+ if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: c %u > maxChan %u\n",
+ __func__, c, maxChan);
+ return false;
+ }
+
+ if ((fband->usePassScan & IS_ECM_CHAN) && !enableExtendedChannels) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "Skipping ecm channel\n");
+ return false;
+ }
+
+ if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == ATH9K_M_HOSTAP)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "Skipping HOSTAP channel\n");
+ return false;
+ }
+
+ if (IS_HT40_MODE(cm->mode) &&
+ !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_FCC_DFS_HT40)) &&
+ (fband->useDfs) &&
+ (rd->conformanceTestLimit != MKK)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "Skipping HT40 channel (en_fcc_dfs_ht40 = 0)\n");
+ return false;
+ }
+
+ if (IS_HT40_MODE(cm->mode) &&
+ !(ath9k_regd_get_eeprom_reg_ext_bits(ah,
+ REG_EXT_JAPAN_NONDFS_HT40)) &&
+ !(fband->useDfs) && (rd->conformanceTestLimit == MKK)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "Skipping HT40 channel (en_jap_ht40 = 0)\n");
+ return false;
+ }
+
+ if (IS_HT40_MODE(cm->mode) &&
+ !(ath9k_regd_get_eeprom_reg_ext_bits(ah, REG_EXT_JAPAN_DFS_HT40)) &&
+ (fband->useDfs) &&
+ (rd->conformanceTestLimit == MKK)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "Skipping HT40 channel (en_jap_dfs_ht40 = 0)\n");
+ return false;
+ }
+
+ /* Calculate channel flags */
+
+ channelFlags = cm->flags;
+
+ switch (fband->channelBW) {
+ case CHANNEL_HALF_BW:
+ channelFlags |= CHANNEL_HALF;
+ break;
+ case CHANNEL_QUARTER_BW:
+ channelFlags |= CHANNEL_QUARTER;
+ break;
+ }
+
+ if (fband->usePassScan & rd->pscan)
+ channelFlags |= CHANNEL_PASSIVE;
+ else
+ channelFlags &= ~CHANNEL_PASSIVE;
+ if (fband->useDfs & rd->dfsMask)
+ privFlags = CHANNEL_DFS;
+ else
+ privFlags = 0;
+ if (rd->flags & LIMIT_FRAME_4MS)
+ privFlags |= CHANNEL_4MS_LIMIT;
+ if (privFlags & CHANNEL_DFS)
+ privFlags |= CHANNEL_DISALLOW_ADHOC;
+ if (rd->flags & ADHOC_PER_11D)
+ privFlags |= CHANNEL_PER_11D_ADHOC;
+
+ if (channelFlags & CHANNEL_PASSIVE) {
+ if ((c < 2412) || (c > 2462)) {
+ if (rd5GHz.regDmnEnum == MKK1 ||
+ rd5GHz.regDmnEnum == MKK2) {
+ u32 regcap = ah->ah_caps.reg_cap;
+ if (!(regcap &
+ (AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
+ AR_EEPROM_EEREGCAP_EN_KK_U2 |
+ AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) &&
+ isUNII1OddChan(c)) {
+ channelFlags &= ~CHANNEL_PASSIVE;
+ } else {
+ privFlags |= CHANNEL_DISALLOW_ADHOC;
+ }
+ } else {
+ privFlags |= CHANNEL_DISALLOW_ADHOC;
+ }
+ }
+ }
+
+ if ((cm->mode == ATH9K_MODE_11A) ||
+ (cm->mode == ATH9K_MODE_11NA_HT20) ||
+ (cm->mode == ATH9K_MODE_11NA_HT40PLUS) ||
+ (cm->mode == ATH9K_MODE_11NA_HT40MINUS)) {
+ if (rd->flags & (ADHOC_NO_11A | DISALLOW_ADHOC_11A))
+ privFlags |= CHANNEL_DISALLOW_ADHOC;
+ }
+
+ /* Fill in channel details */
+
+ ret = ath9k_regd_is_chan_present(ah, c);
+ if (ret == -1) {
+ chan = &ah->ah_channels[pos];
+ chan->channel = c;
+ chan->maxRegTxPower = fband->powerDfs;
+ chan->antennaMax = fband->antennaMax;
+ chan->regDmnFlags = rd->flags;
+ chan->maxTxPower = AR5416_MAX_RATE_POWER;
+ chan->minTxPower = AR5416_MAX_RATE_POWER;
+ chan->channelFlags = channelFlags;
+ chan->privFlags = privFlags;
+ } else {
+ chan = &ah->ah_channels[ret];
+ chan->channelFlags |= channelFlags;
+ chan->privFlags |= privFlags;
+ }
+
+ /* Set CTLs */
+
+ if ((cm->flags & CHANNEL_ALL) == CHANNEL_A)
+ chan->conformanceTestLimit[0] = ctl;
+ else if ((cm->flags & CHANNEL_ALL) == CHANNEL_B)
+ chan->conformanceTestLimit[1] = ctl;
+ else if ((cm->flags & CHANNEL_ALL) == CHANNEL_G)
+ chan->conformanceTestLimit[2] = ctl;
+
+ return (ret == -1) ? true : false;
+}
+
+static bool ath9k_regd_japan_check(struct ath_hal *ah,
+ int b,
+ struct regDomain *rd5GHz)
+{
+ bool skipband = false;
+ int i;
+ u32 regcap;
+
+ for (i = 0; i < ARRAY_SIZE(j_bandcheck); i++) {
+ if (j_bandcheck[i].freqbandbit == b) {
+ regcap = ah->ah_caps.reg_cap;
+ if ((j_bandcheck[i].eepromflagtocheck & regcap) == 0) {
+ skipband = true;
+ } else if ((regcap & AR_EEPROM_EEREGCAP_EN_KK_U2) ||
+ (regcap & AR_EEPROM_EEREGCAP_EN_KK_MIDBAND)) {
+ rd5GHz->dfsMask |= DFS_MKK4;
+ rd5GHz->pscan |= PSCAN_MKK3;
+ }
+ break;
+ }
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: Skipping %d freq band\n",
+ __func__, j_bandcheck[i].freqbandbit);
+
+ return skipband;
+}
+
+bool
+ath9k_regd_init_channels(struct ath_hal *ah,
+ u32 maxchans,
+ u32 *nchans, u8 *regclassids,
+ u32 maxregids, u32 *nregids, u16 cc,
+ bool enableOutdoor,
+ bool enableExtendedChannels)
+{
+ u16 maxChan = 7000;
+ struct country_code_to_enum_rd *country = NULL;
+ struct regDomain rd5GHz, rd2GHz;
+ const struct cmode *cm;
+ struct ath9k_channel *ichans = &ah->ah_channels[0];
+ int next = 0, b;
+ u8 ctl;
+ int regdmn;
+ u16 chanSep;
+ unsigned long *modes_avail;
+ DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX);
+
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: cc %u %s %s\n",
+ __func__, cc,
+ enableOutdoor ? "Enable outdoor" : "",
+ enableExtendedChannels ? "Enable ecm" : "");
+
+ if (!ath9k_regd_is_ccode_valid(ah, cc)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: invalid country code %d\n", __func__, cc);
+ return false;
+ }
+
+ if (!ath9k_regd_is_eeprom_valid(ah)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: invalid EEPROM contents\n", __func__);
+ return false;
+ }
+
+ ah->ah_countryCode = ath9k_regd_get_default_country(ah);
+
+ if (ah->ah_countryCode == CTRY_DEFAULT) {
+ ah->ah_countryCode = cc & COUNTRY_CODE_MASK;
+ if ((ah->ah_countryCode == CTRY_DEFAULT) &&
+ (ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)) {
+ ah->ah_countryCode = CTRY_UNITED_STATES;
+ }
+ }
+
+#ifdef AH_SUPPORT_11D
+ if (ah->ah_countryCode == CTRY_DEFAULT) {
+ regdmn = ath9k_regd_get_eepromRD(ah);
+ country = NULL;
+ } else {
+#endif
+ country = ath9k_regd_find_country(ah->ah_countryCode);
+ if (country == NULL) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "Country is NULL!!!!, cc= %d\n",
+ ah->ah_countryCode);
+ return false;
+ } else {
+ regdmn = country->regDmnEnum;
+#ifdef AH_SUPPORT_11D
+ if (((ath9k_regd_get_eepromRD(ah) &
+ WORLD_SKU_MASK) == WORLD_SKU_PREFIX) &&
+ (cc == CTRY_UNITED_STATES)) {
+ if (!isWwrSKU_NoMidband(ah)
+ && ath9k_regd_is_fcc_midband_supported(ah))
+ regdmn = FCC3_FCCA;
+ else
+ regdmn = FCC1_FCCA;
+ }
+#endif
+ }
+#ifdef AH_SUPPORT_11D
+ }
+#endif
+ if (!ath9k_regd_get_wmode_regdomain(ah,
+ regdmn,
+ ~CHANNEL_2GHZ,
+ &rd5GHz)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: couldn't find unitary "
+ "5GHz reg domain for country %u\n",
+ __func__, ah->ah_countryCode);
+ return false;
+ }
+ if (!ath9k_regd_get_wmode_regdomain(ah,
+ regdmn,
+ CHANNEL_2GHZ,
+ &rd2GHz)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: couldn't find unitary 2GHz "
+ "reg domain for country %u\n",
+ __func__, ah->ah_countryCode);
+ return false;
+ }
+
+ if (!isWwrSKU(ah) && ((rd5GHz.regDmnEnum == FCC1) ||
+ (rd5GHz.regDmnEnum == FCC2))) {
+ if (ath9k_regd_is_fcc_midband_supported(ah)) {
+ if (!ath9k_regd_get_wmode_regdomain(ah,
+ FCC3_FCCA,
+ ~CHANNEL_2GHZ,
+ &rd5GHz)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: couldn't find unitary 5GHz "
+ "reg domain for country %u\n",
+ __func__, ah->ah_countryCode);
+ return false;
+ }
+ }
+ }
+
+ if (country == NULL) {
+ modes_avail = ah->ah_caps.wireless_modes;
+ } else {
+ ath9k_regd_get_wmodes_nreg(ah, country, &rd5GHz, modes_allowed);
+ modes_avail = modes_allowed;
+
+ if (!enableOutdoor)
+ maxChan = country->outdoorChanStart;
+ }
+
+ next = 0;
+
+ if (maxchans > ARRAY_SIZE(ah->ah_channels))
+ maxchans = ARRAY_SIZE(ah->ah_channels);
+
+ for (cm = modes; cm < &modes[ARRAY_SIZE(modes)]; cm++) {
+ u16 c, c_hi, c_lo;
+ u64 *channelBM = NULL;
+ struct regDomain *rd = NULL;
+ struct RegDmnFreqBand *fband = NULL, *freqs;
+ int8_t low_adj = 0, hi_adj = 0;
+
+ if (!test_bit(cm->mode, modes_avail)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: !avail mode %d flags 0x%x\n",
+ __func__, cm->mode, cm->flags);
+ continue;
+ }
+ if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: channels 0x%x not supported "
+ "by hardware\n",
+ __func__, cm->flags);
+ continue;
+ }
+
+ switch (cm->mode) {
+ case ATH9K_MODE_11A:
+ case ATH9K_MODE_11NA_HT20:
+ case ATH9K_MODE_11NA_HT40PLUS:
+ case ATH9K_MODE_11NA_HT40MINUS:
+ rd = &rd5GHz;
+ channelBM = rd->chan11a;
+ freqs = &regDmn5GhzFreq[0];
+ ctl = rd->conformanceTestLimit;
+ break;
+ case ATH9K_MODE_11B:
+ rd = &rd2GHz;
+ channelBM = rd->chan11b;
+ freqs = &regDmn2GhzFreq[0];
+ ctl = rd->conformanceTestLimit | CTL_11B;
+ break;
+ case ATH9K_MODE_11G:
+ case ATH9K_MODE_11NG_HT20:
+ case ATH9K_MODE_11NG_HT40PLUS:
+ case ATH9K_MODE_11NG_HT40MINUS:
+ rd = &rd2GHz;
+ channelBM = rd->chan11g;
+ freqs = &regDmn2Ghz11gFreq[0];
+ ctl = rd->conformanceTestLimit | CTL_11G;
+ break;
+ default:
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: Unknown HAL mode 0x%x\n", __func__,
+ cm->mode);
+ continue;
+ }
+
+ if (ath9k_regd_is_chan_bm_zero(channelBM))
+ continue;
+
+ if ((cm->mode == ATH9K_MODE_11NA_HT40PLUS) ||
+ (cm->mode == ATH9K_MODE_11NG_HT40PLUS)) {
+ hi_adj = -20;
+ }
+
+ if ((cm->mode == ATH9K_MODE_11NA_HT40MINUS) ||
+ (cm->mode == ATH9K_MODE_11NG_HT40MINUS)) {
+ low_adj = 20;
+ }
+
+ /* XXX: Add a helper here instead */
+ for (b = 0; b < 64 * BMLEN; b++) {
+ if (ath9k_regd_is_bit_set(b, channelBM)) {
+ fband = &freqs[b];
+ if (rd5GHz.regDmnEnum == MKK1
+ || rd5GHz.regDmnEnum == MKK2) {
+ if (ath9k_regd_japan_check(ah,
+ b,
+ &rd5GHz))
+ continue;
+ }
+
+ ath9k_regd_add_reg_classid(regclassids,
+ maxregids,
+ nregids,
+ fband->
+ regClassId);
+
+ if (IS_HT40_MODE(cm->mode) && (rd == &rd5GHz)) {
+ chanSep = 40;
+ if (fband->lowChannel == 5280)
+ low_adj += 20;
+
+ if (fband->lowChannel == 5170)
+ continue;
+ } else
+ chanSep = fband->channelSep;
+
+ for (c = fband->lowChannel + low_adj;
+ ((c <= (fband->highChannel + hi_adj)) &&
+ (c >= (fband->lowChannel + low_adj)));
+ c += chanSep) {
+ if (next >= maxchans) {
+ DPRINTF(ah->ah_sc,
+ ATH_DBG_REGULATORY,
+ "%s: too many channels "
+ "for channel table\n",
+ __func__);
+ goto done;
+ }
+ if (ath9k_regd_add_channel(ah,
+ c, c_lo, c_hi,
+ maxChan, ctl,
+ next,
+ rd5GHz,
+ fband, rd, cm,
+ ichans,
+ enableExtendedChannels))
+ next++;
+ }
+ if (IS_HT40_MODE(cm->mode) &&
+ (fband->lowChannel == 5280)) {
+ low_adj -= 20;
+ }
+ }
+ }
+ }
+done:
+ if (next != 0) {
+ int i;
+
+ if (next > ARRAY_SIZE(ah->ah_channels)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: too many channels %u; truncating to %u\n",
+ __func__, next,
+ (int) ARRAY_SIZE(ah->ah_channels));
+ next = ARRAY_SIZE(ah->ah_channels);
+ }
+#ifdef ATH_NF_PER_CHAN
+ ath9k_regd_init_rf_buffer(ichans, next);
+#endif
+ ath9k_regd_sort(ichans, next,
+ sizeof(struct ath9k_channel),
+ ath9k_regd_chansort);
+
+ ah->ah_nchan = next;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Channel list:\n");
+ for (i = 0; i < next; i++) {
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "chan: %d flags: 0x%x\n",
+ ah->ah_channels[i].channel,
+ ah->ah_channels[i].channelFlags);
+ }
+ }
+ *nchans = next;
+
+ ah->ah_countryCode = ah->ah_countryCode;
+
+ ah->ah_currentRDInUse = regdmn;
+ ah->ah_currentRD5G = rd5GHz.regDmnEnum;
+ ah->ah_currentRD2G = rd2GHz.regDmnEnum;
+ if (country == NULL) {
+ ah->ah_iso[0] = 0;
+ ah->ah_iso[1] = 0;
+ } else {
+ ah->ah_iso[0] = country->isoName[0];
+ ah->ah_iso[1] = country->isoName[1];
+ }
+
+ return next != 0;
+}
+
+struct ath9k_channel*
+ath9k_regd_check_channel(struct ath_hal *ah,
+ const struct ath9k_channel *c)
+{
+ struct ath9k_channel *base, *cc;
+
+ int flags = c->channelFlags & CHAN_FLAGS;
+ int n, lim;
+
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: channel %u/0x%x (0x%x) requested\n", __func__,
+ c->channel, c->channelFlags, flags);
+
+ cc = ah->ah_curchan;
+ if (cc != NULL && cc->channel == c->channel &&
+ (cc->channelFlags & CHAN_FLAGS) == flags) {
+ if ((cc->privFlags & CHANNEL_INTERFERENCE) &&
+ (cc->privFlags & CHANNEL_DFS))
+ return NULL;
+ else
+ return cc;
+ }
+
+ base = ah->ah_channels;
+ n = ah->ah_nchan;
+
+ for (lim = n; lim != 0; lim >>= 1) {
+ int d;
+ cc = &base[lim >> 1];
+ d = c->channel - cc->channel;
+ if (d == 0) {
+ if ((cc->channelFlags & CHAN_FLAGS) == flags) {
+ if ((cc->privFlags & CHANNEL_INTERFERENCE) &&
+ (cc->privFlags & CHANNEL_DFS))
+ return NULL;
+ else
+ return cc;
+ }
+ d = flags - (cc->channelFlags & CHAN_FLAGS);
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
+ "%s: channel %u/0x%x d %d\n", __func__,
+ cc->channel, cc->channelFlags, d);
+ if (d > 0) {
+ base = cc + 1;
+ lim--;
+ }
+ }
+ DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: no match for %u/0x%x\n",
+ __func__, c->channel, c->channelFlags);
+ return NULL;
+}
+
+u32
+ath9k_regd_get_antenna_allowed(struct ath_hal *ah,
+ struct ath9k_channel *chan)
+{
+ struct ath9k_channel *ichan = NULL;
+
+ ichan = ath9k_regd_check_channel(ah, chan);
+ if (!ichan)
+ return 0;
+
+ return ichan->antennaMax;
+}
+
+u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan)
+{
+ u32 ctl = NO_CTL;
+ struct ath9k_channel *ichan;
+
+ if (ah->ah_countryCode == CTRY_DEFAULT && isWwrSKU(ah)) {
+ if (IS_CHAN_B(chan))
+ ctl = SD_NO_CTL | CTL_11B;
+ else if (IS_CHAN_G(chan))
+ ctl = SD_NO_CTL | CTL_11G;
+ else
+ ctl = SD_NO_CTL | CTL_11A;
+ } else {
+ ichan = ath9k_regd_check_channel(ah, chan);
+ if (ichan != NULL) {
+ /* FIXME */
+ if (IS_CHAN_A(ichan))
+ ctl = ichan->conformanceTestLimit[0];
+ else if (IS_CHAN_B(ichan))
+ ctl = ichan->conformanceTestLimit[1];
+ else if (IS_CHAN_G(ichan))
+ ctl = ichan->conformanceTestLimit[2];
+
+ if (IS_CHAN_G(chan) && (ctl & 0xf) == CTL_11B)
+ ctl = (ctl & ~0xf) | CTL_11G;
+ }
+ }
+ return ctl;
+}
+
+void ath9k_regd_get_current_country(struct ath_hal *ah,
+ struct ath9k_country_entry *ctry)
+{
+ u16 rd = ath9k_regd_get_eepromRD(ah);
+
+ ctry->isMultidomain = false;
+ if (rd == CTRY_DEFAULT)
+ ctry->isMultidomain = true;
+ else if (!(rd & COUNTRY_ERD_FLAG))
+ ctry->isMultidomain = isWwrSKU(ah);
+
+ ctry->countryCode = ah->ah_countryCode;
+ ctry->regDmnEnum = ah->ah_currentRD;
+ ctry->regDmn5G = ah->ah_currentRD5G;
+ ctry->regDmn2G = ah->ah_currentRD2G;
+ ctry->iso[0] = ah->ah_iso[0];
+ ctry->iso[1] = ah->ah_iso[1];
+ ctry->iso[2] = ah->ah_iso[2];
+}
diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h
new file mode 100644
index 00000000000..0ecd344fbd9
--- /dev/null
+++ b/drivers/net/wireless/ath9k/regd.h
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef REGD_H
+#define REGD_H
+
+#include "ath9k.h"
+
+#define BMLEN 2
+#define BMZERO {(u64) 0, (u64) 0}
+
+#define BM(_fa, _fb, _fc, _fd, _fe, _ff, _fg, _fh, _fi, _fj, _fk, _fl) \
+ {((((_fa >= 0) && (_fa < 64)) ? \
+ (((u64) 1) << _fa) : (u64) 0) | \
+ (((_fb >= 0) && (_fb < 64)) ? \
+ (((u64) 1) << _fb) : (u64) 0) | \
+ (((_fc >= 0) && (_fc < 64)) ? \
+ (((u64) 1) << _fc) : (u64) 0) | \
+ (((_fd >= 0) && (_fd < 64)) ? \
+ (((u64) 1) << _fd) : (u64) 0) | \
+ (((_fe >= 0) && (_fe < 64)) ? \
+ (((u64) 1) << _fe) : (u64) 0) | \
+ (((_ff >= 0) && (_ff < 64)) ? \
+ (((u64) 1) << _ff) : (u64) 0) | \
+ (((_fg >= 0) && (_fg < 64)) ? \
+ (((u64) 1) << _fg) : (u64) 0) | \
+ (((_fh >= 0) && (_fh < 64)) ? \
+ (((u64) 1) << _fh) : (u64) 0) | \
+ (((_fi >= 0) && (_fi < 64)) ? \
+ (((u64) 1) << _fi) : (u64) 0) | \
+ (((_fj >= 0) && (_fj < 64)) ? \
+ (((u64) 1) << _fj) : (u64) 0) | \
+ (((_fk >= 0) && (_fk < 64)) ? \
+ (((u64) 1) << _fk) : (u64) 0) | \
+ (((_fl >= 0) && (_fl < 64)) ? \
+ (((u64) 1) << _fl) : (u64) 0) | \
+ ((((_fa > 63) && (_fa < 128)) ? \
+ (((u64) 1) << (_fa - 64)) : (u64) 0) | \
+ (((_fb > 63) && (_fb < 128)) ? \
+ (((u64) 1) << (_fb - 64)) : (u64) 0) | \
+ (((_fc > 63) && (_fc < 128)) ? \
+ (((u64) 1) << (_fc - 64)) : (u64) 0) | \
+ (((_fd > 63) && (_fd < 128)) ? \
+ (((u64) 1) << (_fd - 64)) : (u64) 0) | \
+ (((_fe > 63) && (_fe < 128)) ? \
+ (((u64) 1) << (_fe - 64)) : (u64) 0) | \
+ (((_ff > 63) && (_ff < 128)) ? \
+ (((u64) 1) << (_ff - 64)) : (u64) 0) | \
+ (((_fg > 63) && (_fg < 128)) ? \
+ (((u64) 1) << (_fg - 64)) : (u64) 0) | \
+ (((_fh > 63) && (_fh < 128)) ? \
+ (((u64) 1) << (_fh - 64)) : (u64) 0) | \
+ (((_fi > 63) && (_fi < 128)) ? \
+ (((u64) 1) << (_fi - 64)) : (u64) 0) | \
+ (((_fj > 63) && (_fj < 128)) ? \
+ (((u64) 1) << (_fj - 64)) : (u64) 0) | \
+ (((_fk > 63) && (_fk < 128)) ? \
+ (((u64) 1) << (_fk - 64)) : (u64) 0) | \
+ (((_fl > 63) && (_fl < 128)) ? \
+ (((u64) 1) << (_fl - 64)) : (u64) 0)))}
+
+#define DEF_REGDMN FCC1_FCCA
+#define DEF_DMN_5 FCC1
+#define DEF_DMN_2 FCCA
+#define COUNTRY_ERD_FLAG 0x8000
+#define WORLDWIDE_ROAMING_FLAG 0x4000
+#define SUPER_DOMAIN_MASK 0x0fff
+#define COUNTRY_CODE_MASK 0x3fff
+#define CF_INTERFERENCE (CHANNEL_CW_INT | CHANNEL_RADAR_INT)
+#define CHANNEL_14 (2484)
+#define IS_11G_CH14(_ch,_cf) \
+ (((_ch) == CHANNEL_14) && ((_cf) == CHANNEL_G))
+
+#define NO_PSCAN 0x0ULL
+#define PSCAN_FCC 0x0000000000000001ULL
+#define PSCAN_FCC_T 0x0000000000000002ULL
+#define PSCAN_ETSI 0x0000000000000004ULL
+#define PSCAN_MKK1 0x0000000000000008ULL
+#define PSCAN_MKK2 0x0000000000000010ULL
+#define PSCAN_MKKA 0x0000000000000020ULL
+#define PSCAN_MKKA_G 0x0000000000000040ULL
+#define PSCAN_ETSIA 0x0000000000000080ULL
+#define PSCAN_ETSIB 0x0000000000000100ULL
+#define PSCAN_ETSIC 0x0000000000000200ULL
+#define PSCAN_WWR 0x0000000000000400ULL
+#define PSCAN_MKKA1 0x0000000000000800ULL
+#define PSCAN_MKKA1_G 0x0000000000001000ULL
+#define PSCAN_MKKA2 0x0000000000002000ULL
+#define PSCAN_MKKA2_G 0x0000000000004000ULL
+#define PSCAN_MKK3 0x0000000000008000ULL
+#define PSCAN_DEFER 0x7FFFFFFFFFFFFFFFULL
+#define IS_ECM_CHAN 0x8000000000000000ULL
+
+#define isWwrSKU(_ah) \
+ (((ath9k_regd_get_eepromRD((_ah)) & WORLD_SKU_MASK) == \
+ WORLD_SKU_PREFIX) || \
+ (ath9k_regd_get_eepromRD(_ah) == WORLD))
+
+#define isWwrSKU_NoMidband(_ah) \
+ ((ath9k_regd_get_eepromRD((_ah)) == WOR3_WORLD) || \
+ (ath9k_regd_get_eepromRD(_ah) == WOR4_WORLD) || \
+ (ath9k_regd_get_eepromRD(_ah) == WOR5_ETSIC))
+
+#define isUNII1OddChan(ch) \
+ ((ch == 5170) || (ch == 5190) || (ch == 5210) || (ch == 5230))
+
+#define IS_HT40_MODE(_mode) \
+ (((_mode == ATH9K_MODE_11NA_HT40PLUS || \
+ _mode == ATH9K_MODE_11NG_HT40PLUS || \
+ _mode == ATH9K_MODE_11NA_HT40MINUS || \
+ _mode == ATH9K_MODE_11NG_HT40MINUS) ? true : false))
+
+#define CHAN_FLAGS (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER)
+
+#define swap(_a, _b, _size) { \
+ u8 *s = _b; \
+ int i = _size; \
+ do { \
+ u8 tmp = *_a; \
+ *_a++ = *s; \
+ *s++ = tmp; \
+ } while (--i); \
+ _a -= _size; \
+}
+
+
+#define HALF_MAXCHANBW 10
+
+#define MULTI_DOMAIN_MASK 0xFF00
+
+#define WORLD_SKU_MASK 0x00F0
+#define WORLD_SKU_PREFIX 0x0060
+
+#define CHANNEL_HALF_BW 10
+#define CHANNEL_QUARTER_BW 5
+
+typedef int ath_hal_cmp_t(const void *, const void *);
+
+struct reg_dmn_pair_mapping {
+ u16 regDmnEnum;
+ u16 regDmn5GHz;
+ u16 regDmn2GHz;
+ u32 flags5GHz;
+ u32 flags2GHz;
+ u64 pscanMask;
+ u16 singleCC;
+};
+
+struct ccmap {
+ char isoName[3];
+ u16 countryCode;
+};
+
+struct country_code_to_enum_rd {
+ u16 countryCode;
+ u16 regDmnEnum;
+ const char *isoName;
+ const char *name;
+ bool allow11g;
+ bool allow11aTurbo;
+ bool allow11gTurbo;
+ bool allow11ng20;
+ bool allow11ng40;
+ bool allow11na20;
+ bool allow11na40;
+ u16 outdoorChanStart;
+};
+
+struct RegDmnFreqBand {
+ u16 lowChannel;
+ u16 highChannel;
+ u8 powerDfs;
+ u8 antennaMax;
+ u8 channelBW;
+ u8 channelSep;
+ u64 useDfs;
+ u64 usePassScan;
+ u8 regClassId;
+};
+
+struct regDomain {
+ u16 regDmnEnum;
+ u8 conformanceTestLimit;
+ u64 dfsMask;
+ u64 pscan;
+ u32 flags;
+ u64 chan11a[BMLEN];
+ u64 chan11a_turbo[BMLEN];
+ u64 chan11a_dyn_turbo[BMLEN];
+ u64 chan11b[BMLEN];
+ u64 chan11g[BMLEN];
+ u64 chan11g_turbo[BMLEN];
+};
+
+struct cmode {
+ u32 mode;
+ u32 flags;
+};
+
+#define YES true
+#define NO false
+
+struct japan_bandcheck {
+ u16 freqbandbit;
+ u32 eepromflagtocheck;
+};
+
+struct common_mode_power {
+ u16 lchan;
+ u16 hchan;
+ u8 pwrlvl;
+};
+
+enum CountryCode {
+ CTRY_ALBANIA = 8,
+ CTRY_ALGERIA = 12,
+ CTRY_ARGENTINA = 32,
+ CTRY_ARMENIA = 51,
+ CTRY_AUSTRALIA = 36,
+ CTRY_AUSTRIA = 40,
+ CTRY_AZERBAIJAN = 31,
+ CTRY_BAHRAIN = 48,
+ CTRY_BELARUS = 112,
+ CTRY_BELGIUM = 56,
+ CTRY_BELIZE = 84,
+ CTRY_BOLIVIA = 68,
+ CTRY_BOSNIA_HERZ = 70,
+ CTRY_BRAZIL = 76,
+ CTRY_BRUNEI_DARUSSALAM = 96,
+ CTRY_BULGARIA = 100,
+ CTRY_CANADA = 124,
+ CTRY_CHILE = 152,
+ CTRY_CHINA = 156,
+ CTRY_COLOMBIA = 170,
+ CTRY_COSTA_RICA = 188,
+ CTRY_CROATIA = 191,
+ CTRY_CYPRUS = 196,
+ CTRY_CZECH = 203,
+ CTRY_DENMARK = 208,
+ CTRY_DOMINICAN_REPUBLIC = 214,
+ CTRY_ECUADOR = 218,
+ CTRY_EGYPT = 818,
+ CTRY_EL_SALVADOR = 222,
+ CTRY_ESTONIA = 233,
+ CTRY_FAEROE_ISLANDS = 234,
+ CTRY_FINLAND = 246,
+ CTRY_FRANCE = 250,
+ CTRY_GEORGIA = 268,
+ CTRY_GERMANY = 276,
+ CTRY_GREECE = 300,
+ CTRY_GUATEMALA = 320,
+ CTRY_HONDURAS = 340,
+ CTRY_HONG_KONG = 344,
+ CTRY_HUNGARY = 348,
+ CTRY_ICELAND = 352,
+ CTRY_INDIA = 356,
+ CTRY_INDONESIA = 360,
+ CTRY_IRAN = 364,
+ CTRY_IRAQ = 368,
+ CTRY_IRELAND = 372,
+ CTRY_ISRAEL = 376,
+ CTRY_ITALY = 380,
+ CTRY_JAMAICA = 388,
+ CTRY_JAPAN = 392,
+ CTRY_JORDAN = 400,
+ CTRY_KAZAKHSTAN = 398,
+ CTRY_KENYA = 404,
+ CTRY_KOREA_NORTH = 408,
+ CTRY_KOREA_ROC = 410,
+ CTRY_KOREA_ROC2 = 411,
+ CTRY_KOREA_ROC3 = 412,
+ CTRY_KUWAIT = 414,
+ CTRY_LATVIA = 428,
+ CTRY_LEBANON = 422,
+ CTRY_LIBYA = 434,
+ CTRY_LIECHTENSTEIN = 438,
+ CTRY_LITHUANIA = 440,
+ CTRY_LUXEMBOURG = 442,
+ CTRY_MACAU = 446,
+ CTRY_MACEDONIA = 807,
+ CTRY_MALAYSIA = 458,
+ CTRY_MALTA = 470,
+ CTRY_MEXICO = 484,
+ CTRY_MONACO = 492,
+ CTRY_MOROCCO = 504,
+ CTRY_NEPAL = 524,
+ CTRY_NETHERLANDS = 528,
+ CTRY_NETHERLANDS_ANTILLES = 530,
+ CTRY_NEW_ZEALAND = 554,
+ CTRY_NICARAGUA = 558,
+ CTRY_NORWAY = 578,
+ CTRY_OMAN = 512,
+ CTRY_PAKISTAN = 586,
+ CTRY_PANAMA = 591,
+ CTRY_PAPUA_NEW_GUINEA = 598,
+ CTRY_PARAGUAY = 600,
+ CTRY_PERU = 604,
+ CTRY_PHILIPPINES = 608,
+ CTRY_POLAND = 616,
+ CTRY_PORTUGAL = 620,
+ CTRY_PUERTO_RICO = 630,
+ CTRY_QATAR = 634,
+ CTRY_ROMANIA = 642,
+ CTRY_RUSSIA = 643,
+ CTRY_SAUDI_ARABIA = 682,
+ CTRY_SERBIA_MONTENEGRO = 891,
+ CTRY_SINGAPORE = 702,
+ CTRY_SLOVAKIA = 703,
+ CTRY_SLOVENIA = 705,
+ CTRY_SOUTH_AFRICA = 710,
+ CTRY_SPAIN = 724,
+ CTRY_SRI_LANKA = 144,
+ CTRY_SWEDEN = 752,
+ CTRY_SWITZERLAND = 756,
+ CTRY_SYRIA = 760,
+ CTRY_TAIWAN = 158,
+ CTRY_THAILAND = 764,
+ CTRY_TRINIDAD_Y_TOBAGO = 780,
+ CTRY_TUNISIA = 788,
+ CTRY_TURKEY = 792,
+ CTRY_UAE = 784,
+ CTRY_UKRAINE = 804,
+ CTRY_UNITED_KINGDOM = 826,
+ CTRY_UNITED_STATES = 840,
+ CTRY_UNITED_STATES_FCC49 = 842,
+ CTRY_URUGUAY = 858,
+ CTRY_UZBEKISTAN = 860,
+ CTRY_VENEZUELA = 862,
+ CTRY_VIET_NAM = 704,
+ CTRY_YEMEN = 887,
+ CTRY_ZIMBABWE = 716,
+ CTRY_JAPAN1 = 393,
+ CTRY_JAPAN2 = 394,
+ CTRY_JAPAN3 = 395,
+ CTRY_JAPAN4 = 396,
+ CTRY_JAPAN5 = 397,
+ CTRY_JAPAN6 = 4006,
+ CTRY_JAPAN7 = 4007,
+ CTRY_JAPAN8 = 4008,
+ CTRY_JAPAN9 = 4009,
+ CTRY_JAPAN10 = 4010,
+ CTRY_JAPAN11 = 4011,
+ CTRY_JAPAN12 = 4012,
+ CTRY_JAPAN13 = 4013,
+ CTRY_JAPAN14 = 4014,
+ CTRY_JAPAN15 = 4015,
+ CTRY_JAPAN16 = 4016,
+ CTRY_JAPAN17 = 4017,
+ CTRY_JAPAN18 = 4018,
+ CTRY_JAPAN19 = 4019,
+ CTRY_JAPAN20 = 4020,
+ CTRY_JAPAN21 = 4021,
+ CTRY_JAPAN22 = 4022,
+ CTRY_JAPAN23 = 4023,
+ CTRY_JAPAN24 = 4024,
+ CTRY_JAPAN25 = 4025,
+ CTRY_JAPAN26 = 4026,
+ CTRY_JAPAN27 = 4027,
+ CTRY_JAPAN28 = 4028,
+ CTRY_JAPAN29 = 4029,
+ CTRY_JAPAN30 = 4030,
+ CTRY_JAPAN31 = 4031,
+ CTRY_JAPAN32 = 4032,
+ CTRY_JAPAN33 = 4033,
+ CTRY_JAPAN34 = 4034,
+ CTRY_JAPAN35 = 4035,
+ CTRY_JAPAN36 = 4036,
+ CTRY_JAPAN37 = 4037,
+ CTRY_JAPAN38 = 4038,
+ CTRY_JAPAN39 = 4039,
+ CTRY_JAPAN40 = 4040,
+ CTRY_JAPAN41 = 4041,
+ CTRY_JAPAN42 = 4042,
+ CTRY_JAPAN43 = 4043,
+ CTRY_JAPAN44 = 4044,
+ CTRY_JAPAN45 = 4045,
+ CTRY_JAPAN46 = 4046,
+ CTRY_JAPAN47 = 4047,
+ CTRY_JAPAN48 = 4048,
+ CTRY_JAPAN49 = 4049,
+ CTRY_JAPAN50 = 4050,
+ CTRY_JAPAN51 = 4051,
+ CTRY_JAPAN52 = 4052,
+ CTRY_JAPAN53 = 4053,
+ CTRY_JAPAN54 = 4054,
+ CTRY_JAPAN55 = 4055,
+ CTRY_JAPAN56 = 4056,
+ CTRY_JAPAN57 = 4057,
+ CTRY_JAPAN58 = 4058,
+ CTRY_JAPAN59 = 4059,
+ CTRY_AUSTRALIA2 = 5000,
+ CTRY_CANADA2 = 5001,
+ CTRY_BELGIUM2 = 5002
+};
+
+void ath9k_regd_get_current_country(struct ath_hal *ah,
+ struct ath9k_country_entry *ctry);
+
+#endif
diff --git a/drivers/net/wireless/ath9k/regd_common.h b/drivers/net/wireless/ath9k/regd_common.h
new file mode 100644
index 00000000000..9112c030b1e
--- /dev/null
+++ b/drivers/net/wireless/ath9k/regd_common.h
@@ -0,0 +1,1915 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef REGD_COMMON_H
+#define REGD_COMMON_H
+
+enum EnumRd {
+ NO_ENUMRD = 0x00,
+ NULL1_WORLD = 0x03,
+ NULL1_ETSIB = 0x07,
+ NULL1_ETSIC = 0x08,
+ FCC1_FCCA = 0x10,
+ FCC1_WORLD = 0x11,
+ FCC4_FCCA = 0x12,
+ FCC5_FCCA = 0x13,
+ FCC6_FCCA = 0x14,
+
+ FCC2_FCCA = 0x20,
+ FCC2_WORLD = 0x21,
+ FCC2_ETSIC = 0x22,
+ FCC6_WORLD = 0x23,
+ FRANCE_RES = 0x31,
+ FCC3_FCCA = 0x3A,
+ FCC3_WORLD = 0x3B,
+
+ ETSI1_WORLD = 0x37,
+ ETSI3_ETSIA = 0x32,
+ ETSI2_WORLD = 0x35,
+ ETSI3_WORLD = 0x36,
+ ETSI4_WORLD = 0x30,
+ ETSI4_ETSIC = 0x38,
+ ETSI5_WORLD = 0x39,
+ ETSI6_WORLD = 0x34,
+ ETSI_RESERVED = 0x33,
+
+ MKK1_MKKA = 0x40,
+ MKK1_MKKB = 0x41,
+ APL4_WORLD = 0x42,
+ MKK2_MKKA = 0x43,
+ APL_RESERVED = 0x44,
+ APL2_WORLD = 0x45,
+ APL2_APLC = 0x46,
+ APL3_WORLD = 0x47,
+ MKK1_FCCA = 0x48,
+ APL2_APLD = 0x49,
+ MKK1_MKKA1 = 0x4A,
+ MKK1_MKKA2 = 0x4B,
+ MKK1_MKKC = 0x4C,
+
+ APL3_FCCA = 0x50,
+ APL1_WORLD = 0x52,
+ APL1_FCCA = 0x53,
+ APL1_APLA = 0x54,
+ APL1_ETSIC = 0x55,
+ APL2_ETSIC = 0x56,
+ APL5_WORLD = 0x58,
+ APL6_WORLD = 0x5B,
+ APL7_FCCA = 0x5C,
+ APL8_WORLD = 0x5D,
+ APL9_WORLD = 0x5E,
+
+ WOR0_WORLD = 0x60,
+ WOR1_WORLD = 0x61,
+ WOR2_WORLD = 0x62,
+ WOR3_WORLD = 0x63,
+ WOR4_WORLD = 0x64,
+ WOR5_ETSIC = 0x65,
+
+ WOR01_WORLD = 0x66,
+ WOR02_WORLD = 0x67,
+ EU1_WORLD = 0x68,
+
+ WOR9_WORLD = 0x69,
+ WORA_WORLD = 0x6A,
+ WORB_WORLD = 0x6B,
+
+ MKK3_MKKB = 0x80,
+ MKK3_MKKA2 = 0x81,
+ MKK3_MKKC = 0x82,
+
+ MKK4_MKKB = 0x83,
+ MKK4_MKKA2 = 0x84,
+ MKK4_MKKC = 0x85,
+
+ MKK5_MKKB = 0x86,
+ MKK5_MKKA2 = 0x87,
+ MKK5_MKKC = 0x88,
+
+ MKK6_MKKB = 0x89,
+ MKK6_MKKA2 = 0x8A,
+ MKK6_MKKC = 0x8B,
+
+ MKK7_MKKB = 0x8C,
+ MKK7_MKKA2 = 0x8D,
+ MKK7_MKKC = 0x8E,
+
+ MKK8_MKKB = 0x8F,
+ MKK8_MKKA2 = 0x90,
+ MKK8_MKKC = 0x91,
+
+ MKK14_MKKA1 = 0x92,
+ MKK15_MKKA1 = 0x93,
+
+ MKK10_FCCA = 0xD0,
+ MKK10_MKKA1 = 0xD1,
+ MKK10_MKKC = 0xD2,
+ MKK10_MKKA2 = 0xD3,
+
+ MKK11_MKKA = 0xD4,
+ MKK11_FCCA = 0xD5,
+ MKK11_MKKA1 = 0xD6,
+ MKK11_MKKC = 0xD7,
+ MKK11_MKKA2 = 0xD8,
+
+ MKK12_MKKA = 0xD9,
+ MKK12_FCCA = 0xDA,
+ MKK12_MKKA1 = 0xDB,
+ MKK12_MKKC = 0xDC,
+ MKK12_MKKA2 = 0xDD,
+
+ MKK13_MKKB = 0xDE,
+
+ MKK3_MKKA = 0xF0,
+ MKK3_MKKA1 = 0xF1,
+ MKK3_FCCA = 0xF2,
+ MKK4_MKKA = 0xF3,
+ MKK4_MKKA1 = 0xF4,
+ MKK4_FCCA = 0xF5,
+ MKK9_MKKA = 0xF6,
+ MKK10_MKKA = 0xF7,
+ MKK6_MKKA1 = 0xF8,
+ MKK6_FCCA = 0xF9,
+ MKK7_MKKA1 = 0xFA,
+ MKK7_FCCA = 0xFB,
+ MKK9_FCCA = 0xFC,
+ MKK9_MKKA1 = 0xFD,
+ MKK9_MKKC = 0xFE,
+ MKK9_MKKA2 = 0xFF,
+
+ APL1 = 0x0150,
+ APL2 = 0x0250,
+ APL3 = 0x0350,
+ APL4 = 0x0450,
+ APL5 = 0x0550,
+ APL6 = 0x0650,
+ APL7 = 0x0750,
+ APL8 = 0x0850,
+ APL9 = 0x0950,
+ APL10 = 0x1050,
+
+ ETSI1 = 0x0130,
+ ETSI2 = 0x0230,
+ ETSI3 = 0x0330,
+ ETSI4 = 0x0430,
+ ETSI5 = 0x0530,
+ ETSI6 = 0x0630,
+ ETSIA = 0x0A30,
+ ETSIB = 0x0B30,
+ ETSIC = 0x0C30,
+
+ FCC1 = 0x0110,
+ FCC2 = 0x0120,
+ FCC3 = 0x0160,
+ FCC4 = 0x0165,
+ FCC5 = 0x0510,
+ FCC6 = 0x0610,
+ FCCA = 0x0A10,
+
+ APLD = 0x0D50,
+
+ MKK1 = 0x0140,
+ MKK2 = 0x0240,
+ MKK3 = 0x0340,
+ MKK4 = 0x0440,
+ MKK5 = 0x0540,
+ MKK6 = 0x0640,
+ MKK7 = 0x0740,
+ MKK8 = 0x0840,
+ MKK9 = 0x0940,
+ MKK10 = 0x0B40,
+ MKK11 = 0x1140,
+ MKK12 = 0x1240,
+ MKK13 = 0x0C40,
+ MKK14 = 0x1440,
+ MKK15 = 0x1540,
+ MKKA = 0x0A40,
+ MKKC = 0x0A50,
+
+ NULL1 = 0x0198,
+ WORLD = 0x0199,
+ DEBUG_REG_DMN = 0x01ff,
+};
+
+enum {
+ FCC = 0x10,
+ MKK = 0x40,
+ ETSI = 0x30,
+};
+
+enum {
+ NO_REQ = 0x00000000,
+ DISALLOW_ADHOC_11A = 0x00000001,
+ DISALLOW_ADHOC_11A_TURB = 0x00000002,
+ NEED_NFC = 0x00000004,
+
+ ADHOC_PER_11D = 0x00000008,
+ ADHOC_NO_11A = 0x00000010,
+
+ PUBLIC_SAFETY_DOMAIN = 0x00000020,
+ LIMIT_FRAME_4MS = 0x00000040,
+
+ NO_HOSTAP = 0x00000080,
+
+ REQ_MASK = 0x000000FF,
+};
+
+#define REG_DOMAIN_2GHZ_MASK (REQ_MASK & \
+ (!(ADHOC_NO_11A | DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB)))
+#define REG_DOMAIN_5GHZ_MASK REQ_MASK
+
+static struct reg_dmn_pair_mapping regDomainPairs[] = {
+ {NO_ENUMRD, DEBUG_REG_DMN, DEBUG_REG_DMN, NO_REQ, NO_REQ,
+ PSCAN_DEFER, 0},
+ {NULL1_WORLD, NULL1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {NULL1_ETSIB, NULL1, ETSIB, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {NULL1_ETSIC, NULL1, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+
+ {FCC2_FCCA, FCC2, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {FCC2_WORLD, FCC2, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {FCC2_ETSIC, FCC2, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {FCC3_FCCA, FCC3, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {FCC3_WORLD, FCC3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {FCC4_FCCA, FCC4, FCCA,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {FCC5_FCCA, FCC5, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {FCC6_FCCA, FCC6, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {FCC6_WORLD, FCC6, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+
+ {ETSI1_WORLD, ETSI1, WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {ETSI2_WORLD, ETSI2, WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {ETSI3_WORLD, ETSI3, WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {ETSI4_WORLD, ETSI4, WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {ETSI5_WORLD, ETSI5, WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {ETSI6_WORLD, ETSI6, WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+
+ {ETSI3_ETSIA, ETSI3, WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {FRANCE_RES, ETSI3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+
+ {FCC1_WORLD, FCC1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {FCC1_FCCA, FCC1, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {APL1_WORLD, APL1, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {APL2_WORLD, APL2, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {APL3_WORLD, APL3, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {APL4_WORLD, APL4, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {APL5_WORLD, APL5, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {APL6_WORLD, APL6, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {APL8_WORLD, APL8, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {APL9_WORLD, APL9, WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+
+ {APL3_FCCA, APL3, FCCA, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {APL1_ETSIC, APL1, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {APL2_ETSIC, APL2, ETSIC, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {APL2_APLD, APL2, APLD, NO_REQ, NO_REQ, PSCAN_DEFER,},
+
+ {MKK1_MKKA, MKK1, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKKA, CTRY_JAPAN},
+ {MKK1_MKKB, MKK1, MKKA,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC |
+ LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK1 | PSCAN_MKKA | PSCAN_MKKA_G,
+ CTRY_JAPAN1},
+ {MKK1_FCCA, MKK1, FCCA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1, CTRY_JAPAN2},
+ {MKK1_MKKA1, MKK1, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN4},
+ {MKK1_MKKA2, MKK1, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN5},
+ {MKK1_MKKC, MKK1, MKKC,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1, CTRY_JAPAN6},
+
+ {MKK2_MKKA, MKK2, MKKA,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC |
+ LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK2 | PSCAN_MKKA | PSCAN_MKKA_G,
+ CTRY_JAPAN3},
+
+ {MKK3_MKKA, MKK3, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKKA, CTRY_JAPAN25},
+ {MKK3_MKKB, MKK3, MKKA,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC |
+ LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKKA | PSCAN_MKKA_G,
+ CTRY_JAPAN7},
+ {MKK3_MKKA1, MKK3, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN26},
+ {MKK3_MKKA2, MKK3, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN8},
+ {MKK3_MKKC, MKK3, MKKC,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ NO_PSCAN, CTRY_JAPAN9},
+ {MKK3_FCCA, MKK3, FCCA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ NO_PSCAN, CTRY_JAPAN27},
+
+ {MKK4_MKKA, MKK4, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3, CTRY_JAPAN36},
+ {MKK4_MKKB, MKK4, MKKA,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC |
+ LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G,
+ CTRY_JAPAN10},
+ {MKK4_MKKA1, MKK4, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN28},
+ {MKK4_MKKA2, MKK4, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN11},
+ {MKK4_MKKC, MKK4, MKKC,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3, CTRY_JAPAN12},
+ {MKK4_FCCA, MKK4, FCCA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3, CTRY_JAPAN29},
+
+ {MKK5_MKKB, MKK5, MKKA,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC |
+ LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G,
+ CTRY_JAPAN13},
+ {MKK5_MKKA2, MKK5, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN14},
+ {MKK5_MKKC, MKK5, MKKC,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3, CTRY_JAPAN15},
+
+ {MKK6_MKKB, MKK6, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKKA | PSCAN_MKKA_G, CTRY_JAPAN16},
+ {MKK6_MKKA1, MKK6, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN30},
+ {MKK6_MKKA2, MKK6, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN17},
+ {MKK6_MKKC, MKK6, MKKC,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1, CTRY_JAPAN18},
+ {MKK6_FCCA, MKK6, FCCA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ NO_PSCAN, CTRY_JAPAN31},
+
+ {MKK7_MKKB, MKK7, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G,
+ CTRY_JAPAN19},
+ {MKK7_MKKA1, MKK7, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN32},
+ {MKK7_MKKA2, MKK7, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G,
+ CTRY_JAPAN20},
+ {MKK7_MKKC, MKK7, MKKC,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN21},
+ {MKK7_FCCA, MKK7, FCCA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN33},
+
+ {MKK8_MKKB, MKK8, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G,
+ CTRY_JAPAN22},
+ {MKK8_MKKA2, MKK8, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G,
+ CTRY_JAPAN23},
+ {MKK8_MKKC, MKK8, MKKC,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN24},
+
+ {MKK9_MKKA, MKK9, MKKA,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC |
+ LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK2 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G,
+ CTRY_JAPAN34},
+ {MKK9_FCCA, MKK9, FCCA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ NO_PSCAN, CTRY_JAPAN37},
+ {MKK9_MKKA1, MKK9, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN38},
+ {MKK9_MKKA2, MKK9, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN40},
+ {MKK9_MKKC, MKK9, MKKC,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ NO_PSCAN, CTRY_JAPAN39},
+
+ {MKK10_MKKA, MKK10, MKKA,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC |
+ LIMIT_FRAME_4MS, NEED_NFC, PSCAN_MKK2 | PSCAN_MKK3, CTRY_JAPAN35},
+ {MKK10_FCCA, MKK10, FCCA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ NO_PSCAN, CTRY_JAPAN41},
+ {MKK10_MKKA1, MKK10, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN42},
+ {MKK10_MKKA2, MKK10, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN44},
+ {MKK10_MKKC, MKK10, MKKC,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ NO_PSCAN, CTRY_JAPAN43},
+
+ {MKK11_MKKA, MKK11, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3, CTRY_JAPAN45},
+ {MKK11_FCCA, MKK11, FCCA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3, CTRY_JAPAN46},
+ {MKK11_MKKA1, MKK11, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN47},
+ {MKK11_MKKA2, MKK11, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G, CTRY_JAPAN49},
+ {MKK11_MKKC, MKK11, MKKC,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK3, CTRY_JAPAN48},
+
+ {MKK12_MKKA, MKK12, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN50},
+ {MKK12_FCCA, MKK12, FCCA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN51},
+ {MKK12_MKKA1, MKK12, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA1 | PSCAN_MKKA1_G,
+ CTRY_JAPAN52},
+ {MKK12_MKKA2, MKK12, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA2 | PSCAN_MKKA2_G,
+ CTRY_JAPAN54},
+ {MKK12_MKKC, MKK12, MKKC,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3, CTRY_JAPAN53},
+
+ {MKK13_MKKB, MKK13, MKKA,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB | NEED_NFC |
+ LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKK3 | PSCAN_MKKA | PSCAN_MKKA_G,
+ CTRY_JAPAN57},
+
+ {MKK14_MKKA1, MKK14, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN58},
+ {MKK15_MKKA1, MKK15, MKKA,
+ DISALLOW_ADHOC_11A_TURB | NEED_NFC | LIMIT_FRAME_4MS, NEED_NFC,
+ PSCAN_MKK1 | PSCAN_MKKA1 | PSCAN_MKKA1_G, CTRY_JAPAN59},
+
+ {WOR0_WORLD, WOR0_WORLD, WOR0_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER,
+ 0},
+ {WOR1_WORLD, WOR1_WORLD, WOR1_WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {WOR2_WORLD, WOR2_WORLD, WOR2_WORLD, DISALLOW_ADHOC_11A_TURB,
+ NO_REQ, PSCAN_DEFER, 0},
+ {WOR3_WORLD, WOR3_WORLD, WOR3_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER,
+ 0},
+ {WOR4_WORLD, WOR4_WORLD, WOR4_WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {WOR5_ETSIC, WOR5_ETSIC, WOR5_ETSIC,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {WOR01_WORLD, WOR01_WORLD, WOR01_WORLD, NO_REQ, NO_REQ,
+ PSCAN_DEFER, 0},
+ {WOR02_WORLD, WOR02_WORLD, WOR02_WORLD, NO_REQ, NO_REQ,
+ PSCAN_DEFER, 0},
+ {EU1_WORLD, EU1_WORLD, EU1_WORLD, NO_REQ, NO_REQ, PSCAN_DEFER, 0},
+ {WOR9_WORLD, WOR9_WORLD, WOR9_WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {WORA_WORLD, WORA_WORLD, WORA_WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+ {WORB_WORLD, WORB_WORLD, WORB_WORLD,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB, NO_REQ, PSCAN_DEFER,
+ 0},
+};
+
+#define NO_INTERSECT_REQ 0xFFFFFFFF
+#define NO_UNION_REQ 0
+
+static struct country_code_to_enum_rd allCountries[] = {
+ {CTRY_DEBUG, NO_ENUMRD, "DB", "DEBUG", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_DEFAULT, DEF_REGDMN, "NA", "NO_COUNTRY_SET", YES, YES, YES,
+ YES, YES, YES, YES, 7000},
+ {CTRY_ALBANIA, NULL1_WORLD, "AL", "ALBANIA", YES, NO, YES, YES, NO,
+ NO, NO, 7000},
+ {CTRY_ALGERIA, NULL1_WORLD, "DZ", "ALGERIA", YES, NO, YES, YES, NO,
+ NO, NO, 7000},
+ {CTRY_ARGENTINA, APL3_WORLD, "AR", "ARGENTINA", YES, NO, NO, YES,
+ NO, YES, NO, 7000},
+ {CTRY_ARMENIA, ETSI4_WORLD, "AM", "ARMENIA", YES, NO, YES, YES,
+ YES, NO, NO, 7000},
+ {CTRY_AUSTRALIA, FCC2_WORLD, "AU", "AUSTRALIA", YES, YES, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_AUSTRALIA2, FCC6_WORLD, "AU", "AUSTRALIA2", YES, YES, YES,
+ YES, YES, YES, YES, 7000},
+ {CTRY_AUSTRIA, ETSI1_WORLD, "AT", "AUSTRIA", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ", "AZERBAIJAN", YES, YES, YES,
+ YES, YES, YES, YES, 7000},
+ {CTRY_BAHRAIN, APL6_WORLD, "BH", "BAHRAIN", YES, NO, YES, YES, YES,
+ YES, NO, 7000},
+ {CTRY_BELARUS, ETSI1_WORLD, "BY", "BELARUS", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_BELGIUM, ETSI1_WORLD, "BE", "BELGIUM", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_BELGIUM2, ETSI4_WORLD, "BL", "BELGIUM", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_BELIZE, APL1_ETSIC, "BZ", "BELIZE", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_BOLIVIA, APL1_ETSIC, "BO", "BOLVIA", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA", "BOSNIA_HERZGOWINA", YES, NO,
+ YES, YES, YES, YES, NO, 7000},
+ {CTRY_BRAZIL, FCC3_WORLD, "BR", "BRAZIL", YES, NO, NO, YES, NO,
+ YES, NO, 7000},
+ {CTRY_BRUNEI_DARUSSALAM, APL1_WORLD, "BN", "BRUNEI DARUSSALAM",
+ YES, YES, YES, YES, YES, YES, YES, 7000},
+ {CTRY_BULGARIA, ETSI6_WORLD, "BG", "BULGARIA", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_CANADA, FCC2_FCCA, "CA", "CANADA", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_CANADA2, FCC6_FCCA, "CA", "CANADA2", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_CHILE, APL6_WORLD, "CL", "CHILE", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_CHINA, APL1_WORLD, "CN", "CHINA", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_COLOMBIA, FCC1_FCCA, "CO", "COLOMBIA", YES, NO, YES, YES,
+ YES, YES, NO, 7000},
+ {CTRY_COSTA_RICA, FCC1_WORLD, "CR", "COSTA RICA", YES, NO, YES,
+ YES, YES, YES, NO, 7000},
+ {CTRY_CROATIA, ETSI3_WORLD, "HR", "CROATIA", YES, NO, YES, YES,
+ YES, YES, NO, 7000},
+ {CTRY_CYPRUS, ETSI1_WORLD, "CY", "CYPRUS", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_CZECH, ETSI3_WORLD, "CZ", "CZECH REPUBLIC", YES, NO, YES,
+ YES, YES, YES, YES, 7000},
+ {CTRY_DENMARK, ETSI1_WORLD, "DK", "DENMARK", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_DOMINICAN_REPUBLIC, FCC1_FCCA, "DO", "DOMINICAN REPUBLIC",
+ YES, YES, YES, YES, YES, YES, YES, 7000},
+ {CTRY_ECUADOR, FCC1_WORLD, "EC", "ECUADOR", YES, NO, NO, YES, YES,
+ YES, NO, 7000},
+ {CTRY_EGYPT, ETSI3_WORLD, "EG", "EGYPT", YES, NO, YES, YES, YES,
+ YES, NO, 7000},
+ {CTRY_EL_SALVADOR, FCC1_WORLD, "SV", "EL SALVADOR", YES, NO, YES,
+ YES, YES, YES, NO, 7000},
+ {CTRY_ESTONIA, ETSI1_WORLD, "EE", "ESTONIA", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_FINLAND, ETSI1_WORLD, "FI", "FINLAND", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_FRANCE, ETSI1_WORLD, "FR", "FRANCE", YES, NO, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_GEORGIA, ETSI4_WORLD, "GE", "GEORGIA", YES, YES, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_GERMANY, ETSI1_WORLD, "DE", "GERMANY", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_GREECE, ETSI1_WORLD, "GR", "GREECE", YES, NO, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_GUATEMALA, FCC1_FCCA, "GT", "GUATEMALA", YES, YES, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_HONDURAS, NULL1_WORLD, "HN", "HONDURAS", YES, NO, YES, YES,
+ YES, NO, NO, 7000},
+ {CTRY_HONG_KONG, FCC2_WORLD, "HK", "HONG KONG", YES, YES, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_HUNGARY, ETSI1_WORLD, "HU", "HUNGARY", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_ICELAND, ETSI1_WORLD, "IS", "ICELAND", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_INDIA, APL6_WORLD, "IN", "INDIA", YES, NO, YES, YES, YES,
+ YES, NO, 7000},
+ {CTRY_INDONESIA, APL1_WORLD, "ID", "INDONESIA", YES, NO, YES, YES,
+ YES, YES, NO, 7000},
+ {CTRY_IRAN, APL1_WORLD, "IR", "IRAN", YES, YES, YES, YES, YES, YES,
+ YES, 7000},
+ {CTRY_IRELAND, ETSI1_WORLD, "IE", "IRELAND", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_ISRAEL, NULL1_WORLD, "IL", "ISRAEL", YES, NO, YES, YES, YES,
+ NO, NO, 7000},
+ {CTRY_ITALY, ETSI1_WORLD, "IT", "ITALY", YES, NO, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAMAICA, ETSI1_WORLD, "JM", "JAMAICA", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+
+ {CTRY_JAPAN, MKK1_MKKA, "JP", "JAPAN", YES, NO, NO, YES, YES, YES,
+ YES, 7000},
+ {CTRY_JAPAN1, MKK1_MKKB, "JP", "JAPAN1", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN2, MKK1_FCCA, "JP", "JAPAN2", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN3, MKK2_MKKA, "JP", "JAPAN3", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN4, MKK1_MKKA1, "JP", "JAPAN4", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN5, MKK1_MKKA2, "JP", "JAPAN5", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN6, MKK1_MKKC, "JP", "JAPAN6", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+
+ {CTRY_JAPAN7, MKK3_MKKB, "JP", "JAPAN7", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN8, MKK3_MKKA2, "JP", "JAPAN8", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN9, MKK3_MKKC, "JP", "JAPAN9", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+
+ {CTRY_JAPAN10, MKK4_MKKB, "JP", "JAPAN10", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN11, MKK4_MKKA2, "JP", "JAPAN11", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN12, MKK4_MKKC, "JP", "JAPAN12", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+
+ {CTRY_JAPAN13, MKK5_MKKB, "JP", "JAPAN13", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN14, MKK5_MKKA2, "JP", "JAPAN14", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN15, MKK5_MKKC, "JP", "JAPAN15", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+
+ {CTRY_JAPAN16, MKK6_MKKB, "JP", "JAPAN16", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN17, MKK6_MKKA2, "JP", "JAPAN17", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN18, MKK6_MKKC, "JP", "JAPAN18", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+
+ {CTRY_JAPAN19, MKK7_MKKB, "JP", "JAPAN19", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN20, MKK7_MKKA2, "JP", "JAPAN20", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN21, MKK7_MKKC, "JP", "JAPAN21", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+
+ {CTRY_JAPAN22, MKK8_MKKB, "JP", "JAPAN22", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN23, MKK8_MKKA2, "JP", "JAPAN23", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN24, MKK8_MKKC, "JP", "JAPAN24", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+
+ {CTRY_JAPAN25, MKK3_MKKA, "JP", "JAPAN25", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN26, MKK3_MKKA1, "JP", "JAPAN26", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN27, MKK3_FCCA, "JP", "JAPAN27", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN28, MKK4_MKKA1, "JP", "JAPAN28", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN29, MKK4_FCCA, "JP", "JAPAN29", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN30, MKK6_MKKA1, "JP", "JAPAN30", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN31, MKK6_FCCA, "JP", "JAPAN31", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN32, MKK7_MKKA1, "JP", "JAPAN32", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN33, MKK7_FCCA, "JP", "JAPAN33", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN34, MKK9_MKKA, "JP", "JAPAN34", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN35, MKK10_MKKA, "JP", "JAPAN35", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN36, MKK4_MKKA, "JP", "JAPAN36", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN37, MKK9_FCCA, "JP", "JAPAN37", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN38, MKK9_MKKA1, "JP", "JAPAN38", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN39, MKK9_MKKC, "JP", "JAPAN39", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN40, MKK9_MKKA2, "JP", "JAPAN40", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN41, MKK10_FCCA, "JP", "JAPAN41", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN42, MKK10_MKKA1, "JP", "JAPAN42", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN43, MKK10_MKKC, "JP", "JAPAN43", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN44, MKK10_MKKA2, "JP", "JAPAN44", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN45, MKK11_MKKA, "JP", "JAPAN45", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN46, MKK11_FCCA, "JP", "JAPAN46", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN47, MKK11_MKKA1, "JP", "JAPAN47", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN48, MKK11_MKKC, "JP", "JAPAN48", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN49, MKK11_MKKA2, "JP", "JAPAN49", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN50, MKK12_MKKA, "JP", "JAPAN50", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN51, MKK12_FCCA, "JP", "JAPAN51", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN52, MKK12_MKKA1, "JP", "JAPAN52", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN53, MKK12_MKKC, "JP", "JAPAN53", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN54, MKK12_MKKA2, "JP", "JAPAN54", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+
+ {CTRY_JAPAN57, MKK13_MKKB, "JP", "JAPAN57", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN58, MKK14_MKKA1, "JP", "JAPAN58", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+ {CTRY_JAPAN59, MKK15_MKKA1, "JP", "JAPAN59", YES, NO, NO, YES, YES,
+ YES, YES, 7000},
+
+ {CTRY_JORDAN, ETSI2_WORLD, "JO", "JORDAN", YES, NO, YES, YES, YES,
+ YES, NO, 7000},
+ {CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ", "KAZAKHSTAN", YES, NO, YES,
+ YES, YES, NO, NO, 7000},
+ {CTRY_KOREA_NORTH, APL9_WORLD, "KP", "NORTH KOREA", YES, NO, NO,
+ YES, YES, YES, YES, 7000},
+ {CTRY_KOREA_ROC, APL9_WORLD, "KR", "KOREA REPUBLIC", YES, NO, NO,
+ YES, NO, YES, NO, 7000},
+ {CTRY_KOREA_ROC2, APL2_WORLD, "K2", "KOREA REPUBLIC2", YES, NO, NO,
+ YES, NO, YES, NO, 7000},
+ {CTRY_KOREA_ROC3, APL9_WORLD, "K3", "KOREA REPUBLIC3", YES, NO, NO,
+ YES, NO, YES, NO, 7000},
+ {CTRY_KUWAIT, NULL1_WORLD, "KW", "KUWAIT", YES, NO, YES, YES, YES,
+ NO, NO, 7000},
+ {CTRY_LATVIA, ETSI1_WORLD, "LV", "LATVIA", YES, NO, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_LEBANON, NULL1_WORLD, "LB", "LEBANON", YES, NO, YES, YES,
+ YES, NO, NO, 7000},
+ {CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI", "LIECHTENSTEIN", YES, NO,
+ YES, YES, YES, YES, YES, 7000},
+ {CTRY_LITHUANIA, ETSI1_WORLD, "LT", "LITHUANIA", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU", "LUXEMBOURG", YES, NO, YES,
+ YES, YES, YES, YES, 7000},
+ {CTRY_MACAU, FCC2_WORLD, "MO", "MACAU", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_MACEDONIA, NULL1_WORLD, "MK", "MACEDONIA", YES, NO, YES, YES,
+ YES, NO, NO, 7000},
+ {CTRY_MALAYSIA, APL8_WORLD, "MY", "MALAYSIA", YES, NO, NO, YES, NO,
+ YES, NO, 7000},
+ {CTRY_MALTA, ETSI1_WORLD, "MT", "MALTA", YES, NO, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_MEXICO, FCC1_FCCA, "MX", "MEXICO", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_MONACO, ETSI4_WORLD, "MC", "MONACO", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_MOROCCO, NULL1_WORLD, "MA", "MOROCCO", YES, NO, YES, YES,
+ YES, NO, NO, 7000},
+ {CTRY_NEPAL, APL1_WORLD, "NP", "NEPAL", YES, NO, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_NETHERLANDS, ETSI1_WORLD, "NL", "NETHERLANDS", YES, NO, YES,
+ YES, YES, YES, YES, 7000},
+ {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN",
+ "NETHERLANDS-ANTILLES", YES, NO, YES, YES, YES, YES, YES, 7000},
+ {CTRY_NEW_ZEALAND, FCC2_ETSIC, "NZ", "NEW ZEALAND", YES, NO, YES,
+ YES, YES, YES, NO, 7000},
+ {CTRY_NORWAY, ETSI1_WORLD, "NO", "NORWAY", YES, NO, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_OMAN, APL6_WORLD, "OM", "OMAN", YES, NO, YES, YES, YES, YES,
+ NO, 7000},
+ {CTRY_PAKISTAN, NULL1_WORLD, "PK", "PAKISTAN", YES, NO, YES, YES,
+ YES, NO, NO, 7000},
+ {CTRY_PANAMA, FCC1_FCCA, "PA", "PANAMA", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_PAPUA_NEW_GUINEA, FCC1_WORLD, "PG", "PAPUA NEW GUINEA", YES,
+ YES, YES, YES, YES, YES, YES, 7000},
+ {CTRY_PERU, APL1_WORLD, "PE", "PERU", YES, NO, YES, YES, YES, YES,
+ NO, 7000},
+ {CTRY_PHILIPPINES, APL1_WORLD, "PH", "PHILIPPINES", YES, YES, YES,
+ YES, YES, YES, YES, 7000},
+ {CTRY_POLAND, ETSI1_WORLD, "PL", "POLAND", YES, NO, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_PORTUGAL, ETSI1_WORLD, "PT", "PORTUGAL", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_PUERTO_RICO, FCC1_FCCA, "PR", "PUERTO RICO", YES, YES, YES,
+ YES, YES, YES, YES, 7000},
+ {CTRY_QATAR, NULL1_WORLD, "QA", "QATAR", YES, NO, YES, YES, YES,
+ NO, NO, 7000},
+ {CTRY_ROMANIA, NULL1_WORLD, "RO", "ROMANIA", YES, NO, YES, YES,
+ YES, NO, NO, 7000},
+ {CTRY_RUSSIA, NULL1_WORLD, "RU", "RUSSIA", YES, NO, YES, YES, YES,
+ NO, NO, 7000},
+ {CTRY_SAUDI_ARABIA, NULL1_WORLD, "SA", "SAUDI ARABIA", YES, NO,
+ YES, YES, YES, NO, NO, 7000},
+ {CTRY_SERBIA_MONTENEGRO, ETSI1_WORLD, "CS", "SERBIA & MONTENEGRO",
+ YES, NO, YES, YES, YES, YES, YES, 7000},
+ {CTRY_SINGAPORE, APL6_WORLD, "SG", "SINGAPORE", YES, YES, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_SLOVAKIA, ETSI1_WORLD, "SK", "SLOVAK REPUBLIC", YES, NO, YES,
+ YES, YES, YES, YES, 7000},
+ {CTRY_SLOVENIA, ETSI1_WORLD, "SI", "SLOVENIA", YES, NO, YES, YES,
+ YES, YES, YES, 7000},
+ {CTRY_SOUTH_AFRICA, FCC3_WORLD, "ZA", "SOUTH AFRICA", YES, NO, YES,
+ YES, YES, YES, NO, 7000},
+ {CTRY_SPAIN, ETSI1_WORLD, "ES", "SPAIN", YES, NO, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_SRI_LANKA, FCC3_WORLD, "LK", "SRI LANKA", YES, NO, YES, YES,
+ YES, YES, NO, 7000},
+ {CTRY_SWEDEN, ETSI1_WORLD, "SE", "SWEDEN", YES, NO, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_SWITZERLAND, ETSI1_WORLD, "CH", "SWITZERLAND", YES, NO, YES,
+ YES, YES, YES, YES, 7000},
+ {CTRY_SYRIA, NULL1_WORLD, "SY", "SYRIA", YES, NO, YES, YES, YES,
+ NO, NO, 7000},
+ {CTRY_TAIWAN, APL3_FCCA, "TW", "TAIWAN", YES, YES, YES, YES, YES,
+ YES, YES, 7000},
+ {CTRY_THAILAND, NULL1_WORLD, "TH", "THAILAND", YES, NO, YES, YES,
+ YES, NO, NO, 7000},
+ {CTRY_TRINIDAD_Y_TOBAGO, ETSI4_WORLD, "TT", "TRINIDAD & TOBAGO",
+ YES, NO, YES, YES, YES, YES, NO, 7000},
+ {CTRY_TUNISIA, ETSI3_WORLD, "TN", "TUNISIA", YES, NO, YES, YES,
+ YES, YES, NO, 7000},
+ {CTRY_TURKEY, ETSI3_WORLD, "TR", "TURKEY", YES, NO, YES, YES, YES,
+ YES, NO, 7000},
+ {CTRY_UKRAINE, NULL1_WORLD, "UA", "UKRAINE", YES, NO, YES, YES,
+ YES, NO, NO, 7000},
+ {CTRY_UAE, NULL1_WORLD, "AE", "UNITED ARAB EMIRATES", YES, NO, YES,
+ YES, YES, NO, NO, 7000},
+ {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB", "UNITED KINGDOM", YES, NO,
+ YES, YES, YES, YES, YES, 7000},
+ {CTRY_UNITED_STATES, FCC3_FCCA, "US", "UNITED STATES", YES, YES,
+ YES, YES, YES, YES, YES, 5825},
+ {CTRY_UNITED_STATES_FCC49, FCC4_FCCA, "PS",
+ "UNITED STATES (PUBLIC SAFETY)", YES, YES, YES, YES, YES, YES,
+ YES, 7000},
+ {CTRY_URUGUAY, APL2_WORLD, "UY", "URUGUAY", YES, NO, YES, YES, YES,
+ YES, NO, 7000},
+ {CTRY_UZBEKISTAN, FCC3_FCCA, "UZ", "UZBEKISTAN", YES, YES, YES,
+ YES, YES, YES, YES, 7000},
+ {CTRY_VENEZUELA, APL2_ETSIC, "VE", "VENEZUELA", YES, NO, YES, YES,
+ YES, YES, NO, 7000},
+ {CTRY_VIET_NAM, NULL1_WORLD, "VN", "VIET NAM", YES, NO, YES, YES,
+ YES, NO, NO, 7000},
+ {CTRY_YEMEN, NULL1_WORLD, "YE", "YEMEN", YES, NO, YES, YES, YES,
+ NO, NO, 7000},
+ {CTRY_ZIMBABWE, NULL1_WORLD, "ZW", "ZIMBABWE", YES, NO, YES, YES,
+ YES, NO, NO, 7000}
+};
+
+enum {
+ NO_DFS = 0x0000000000000000ULL,
+ DFS_FCC3 = 0x0000000000000001ULL,
+ DFS_ETSI = 0x0000000000000002ULL,
+ DFS_MKK4 = 0x0000000000000004ULL,
+};
+
+enum {
+ F1_4915_4925,
+ F1_4935_4945,
+ F1_4920_4980,
+ F1_4942_4987,
+ F1_4945_4985,
+ F1_4950_4980,
+ F1_5035_5040,
+ F1_5040_5080,
+ F1_5055_5055,
+
+ F1_5120_5240,
+
+ F1_5170_5230,
+ F2_5170_5230,
+
+ F1_5180_5240,
+ F2_5180_5240,
+ F3_5180_5240,
+ F4_5180_5240,
+ F5_5180_5240,
+ F6_5180_5240,
+ F7_5180_5240,
+ F8_5180_5240,
+
+ F1_5180_5320,
+
+ F1_5240_5280,
+
+ F1_5260_5280,
+
+ F1_5260_5320,
+ F2_5260_5320,
+ F3_5260_5320,
+ F4_5260_5320,
+ F5_5260_5320,
+ F6_5260_5320,
+
+ F1_5260_5700,
+
+ F1_5280_5320,
+
+ F1_5500_5580,
+
+ F1_5500_5620,
+
+ F1_5500_5700,
+ F2_5500_5700,
+ F3_5500_5700,
+ F4_5500_5700,
+ F5_5500_5700,
+
+ F1_5660_5700,
+
+ F1_5745_5805,
+ F2_5745_5805,
+ F3_5745_5805,
+
+ F1_5745_5825,
+ F2_5745_5825,
+ F3_5745_5825,
+ F4_5745_5825,
+ F5_5745_5825,
+ F6_5745_5825,
+
+ W1_4920_4980,
+ W1_5040_5080,
+ W1_5170_5230,
+ W1_5180_5240,
+ W1_5260_5320,
+ W1_5745_5825,
+ W1_5500_5700,
+ A_DEMO_ALL_CHANNELS
+};
+
+static struct RegDmnFreqBand regDmn5GhzFreq[] = {
+ {4915, 4925, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16},
+ {4935, 4945, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 16},
+ {4920, 4980, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 7},
+ {4942, 4987, 27, 6, 5, 5, NO_DFS, PSCAN_FCC, 0},
+ {4945, 4985, 30, 6, 10, 5, NO_DFS, PSCAN_FCC, 0},
+ {4950, 4980, 33, 6, 20, 5, NO_DFS, PSCAN_FCC, 0},
+ {5035, 5040, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12},
+ {5040, 5080, 23, 0, 20, 20, NO_DFS, PSCAN_MKK2, 2},
+ {5055, 5055, 23, 0, 10, 5, NO_DFS, PSCAN_MKK2, 12},
+
+ {5120, 5240, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 0},
+
+ {5170, 5230, 23, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1},
+ {5170, 5230, 20, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK2, 1},
+
+ {5180, 5240, 15, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0},
+ {5180, 5240, 17, 6, 20, 20, NO_DFS, NO_PSCAN, 1},
+ {5180, 5240, 18, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0},
+ {5180, 5240, 20, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0},
+ {5180, 5240, 23, 0, 20, 20, NO_DFS, PSCAN_FCC | PSCAN_ETSI, 0},
+ {5180, 5240, 23, 6, 20, 20, NO_DFS, PSCAN_FCC, 0},
+ {5180, 5240, 20, 0, 20, 20, NO_DFS, PSCAN_MKK1 | PSCAN_MKK3, 0},
+ {5180, 5240, 23, 6, 20, 20, NO_DFS, NO_PSCAN, 0},
+
+ {5180, 5320, 20, 6, 20, 20, NO_DFS, PSCAN_ETSI, 0},
+
+ {5240, 5280, 23, 0, 20, 20, DFS_FCC3, PSCAN_FCC | PSCAN_ETSI, 0},
+
+ {5260, 5280, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI,
+ PSCAN_FCC | PSCAN_ETSI, 0},
+
+ {5260, 5320, 18, 0, 20, 20, DFS_FCC3 | DFS_ETSI,
+ PSCAN_FCC | PSCAN_ETSI, 0},
+
+ {5260, 5320, 20, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4,
+ PSCAN_FCC | PSCAN_ETSI | PSCAN_MKK3, 0},
+
+
+ {5260, 5320, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI,
+ PSCAN_FCC | PSCAN_ETSI, 2},
+ {5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 2},
+ {5260, 5320, 23, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 0},
+ {5260, 5320, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0},
+
+ {5260, 5700, 5, 6, 20, 20, DFS_FCC3 | DFS_ETSI, NO_PSCAN, 0},
+
+ {5280, 5320, 17, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 0},
+
+ {5500, 5580, 23, 6, 20, 20, DFS_FCC3, PSCAN_FCC, 0},
+
+ {5500, 5620, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0},
+
+ {5500, 5700, 20, 6, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_FCC, 4},
+ {5500, 5700, 27, 0, 20, 20, DFS_FCC3 | DFS_ETSI,
+ PSCAN_FCC | PSCAN_ETSI, 0},
+ {5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI,
+ PSCAN_FCC | PSCAN_ETSI, 0},
+ {5500, 5700, 23, 0, 20, 20, DFS_FCC3 | DFS_ETSI | DFS_MKK4,
+ PSCAN_MKK3 | PSCAN_FCC, 0},
+ {5500, 5700, 30, 6, 20, 20, DFS_ETSI, PSCAN_ETSI, 0},
+
+ {5660, 5700, 23, 6, 20, 20, DFS_FCC3, PSCAN_FCC, 0},
+
+ {5745, 5805, 23, 0, 20, 20, NO_DFS, NO_PSCAN, 0},
+ {5745, 5805, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0},
+ {5745, 5805, 30, 6, 20, 20, NO_DFS, PSCAN_ETSI, 0},
+ {5745, 5825, 5, 6, 20, 20, NO_DFS, NO_PSCAN, 0},
+ {5745, 5825, 17, 0, 20, 20, NO_DFS, NO_PSCAN, 0},
+ {5745, 5825, 20, 0, 20, 20, NO_DFS, NO_PSCAN, 0},
+ {5745, 5825, 30, 0, 20, 20, NO_DFS, NO_PSCAN, 0},
+ {5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 3},
+ {5745, 5825, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0},
+
+
+ {4920, 4980, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0},
+ {5040, 5080, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0},
+ {5170, 5230, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0},
+ {5180, 5240, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0},
+ {5260, 5320, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0},
+ {5745, 5825, 30, 0, 20, 20, NO_DFS, PSCAN_WWR, 0},
+ {5500, 5700, 30, 0, 20, 20, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, 0},
+ {4920, 6100, 30, 6, 20, 20, NO_DFS, NO_PSCAN, 0},
+};
+
+enum {
+ T1_5130_5650,
+ T1_5150_5670,
+
+ T1_5200_5200,
+ T2_5200_5200,
+ T3_5200_5200,
+ T4_5200_5200,
+ T5_5200_5200,
+ T6_5200_5200,
+ T7_5200_5200,
+ T8_5200_5200,
+
+ T1_5200_5280,
+ T2_5200_5280,
+ T3_5200_5280,
+ T4_5200_5280,
+ T5_5200_5280,
+ T6_5200_5280,
+
+ T1_5200_5240,
+ T1_5210_5210,
+ T2_5210_5210,
+ T3_5210_5210,
+ T4_5210_5210,
+ T5_5210_5210,
+ T6_5210_5210,
+ T7_5210_5210,
+ T8_5210_5210,
+ T9_5210_5210,
+ T10_5210_5210,
+ T1_5240_5240,
+
+ T1_5210_5250,
+ T1_5210_5290,
+ T2_5210_5290,
+ T3_5210_5290,
+
+ T1_5280_5280,
+ T2_5280_5280,
+ T1_5290_5290,
+ T2_5290_5290,
+ T3_5290_5290,
+ T1_5250_5290,
+ T2_5250_5290,
+ T3_5250_5290,
+ T4_5250_5290,
+
+ T1_5540_5660,
+ T2_5540_5660,
+ T3_5540_5660,
+ T1_5760_5800,
+ T2_5760_5800,
+ T3_5760_5800,
+ T4_5760_5800,
+ T5_5760_5800,
+ T6_5760_5800,
+ T7_5760_5800,
+
+ T1_5765_5805,
+ T2_5765_5805,
+ T3_5765_5805,
+ T4_5765_5805,
+ T5_5765_5805,
+ T6_5765_5805,
+ T7_5765_5805,
+ T8_5765_5805,
+ T9_5765_5805,
+
+ WT1_5210_5250,
+ WT1_5290_5290,
+ WT1_5540_5660,
+ WT1_5760_5800,
+};
+
+enum {
+ F1_2312_2372,
+ F2_2312_2372,
+
+ F1_2412_2472,
+ F2_2412_2472,
+ F3_2412_2472,
+
+ F1_2412_2462,
+ F2_2412_2462,
+
+ F1_2432_2442,
+
+ F1_2457_2472,
+
+ F1_2467_2472,
+
+ F1_2484_2484,
+ F2_2484_2484,
+
+ F1_2512_2732,
+
+ W1_2312_2372,
+ W1_2412_2412,
+ W1_2417_2432,
+ W1_2437_2442,
+ W1_2447_2457,
+ W1_2462_2462,
+ W1_2467_2467,
+ W2_2467_2467,
+ W1_2472_2472,
+ W2_2472_2472,
+ W1_2484_2484,
+ W2_2484_2484,
+};
+
+static struct RegDmnFreqBand regDmn2GhzFreq[] = {
+ {2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+
+ {2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0},
+ {2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+
+ {2412, 2462, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA, 0},
+
+ {2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+
+ {2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+
+ {2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 0},
+
+ {2484, 2484, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2484, 2484, 20, 0, 20, 5, NO_DFS,
+ PSCAN_MKKA | PSCAN_MKKA1 | PSCAN_MKKA2, 0},
+
+ {2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0},
+
+ {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2412, 2412, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2417, 2432, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2437, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2447, 2457, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2462, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2467, 2467, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0},
+ {2467, 2467, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0},
+ {2472, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0},
+ {2472, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0},
+ {2484, 2484, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0},
+ {2484, 2484, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0},
+};
+
+enum {
+ G1_2312_2372,
+ G2_2312_2372,
+
+ G1_2412_2472,
+ G2_2412_2472,
+ G3_2412_2472,
+
+ G1_2412_2462,
+ G2_2412_2462,
+
+ G1_2432_2442,
+
+ G1_2457_2472,
+
+ G1_2512_2732,
+
+ G1_2467_2472,
+
+ WG1_2312_2372,
+ WG1_2412_2462,
+ WG1_2467_2472,
+ WG2_2467_2472,
+ G_DEMO_ALL_CHANNELS
+};
+
+static struct RegDmnFreqBand regDmn2Ghz11gFreq[] = {
+ {2312, 2372, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+
+ {2412, 2472, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2412, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G, 0},
+ {2412, 2472, 30, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+
+ {2412, 2462, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2412, 2462, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA_G, 0},
+
+ {2432, 2442, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+
+ {2457, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+
+ {2512, 2732, 5, 6, 20, 5, NO_DFS, NO_PSCAN, 0},
+
+ {2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_MKKA2 | PSCAN_MKKA, 0},
+
+ {2312, 2372, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2412, 2462, 20, 0, 20, 5, NO_DFS, NO_PSCAN, 0},
+ {2467, 2472, 20, 0, 20, 5, NO_DFS, PSCAN_WWR | IS_ECM_CHAN, 0},
+ {2467, 2472, 20, 0, 20, 5, NO_DFS, NO_PSCAN | IS_ECM_CHAN, 0},
+ {2312, 2732, 27, 6, 20, 5, NO_DFS, NO_PSCAN, 0},
+};
+
+enum {
+ T1_2312_2372,
+ T1_2437_2437,
+ T2_2437_2437,
+ T3_2437_2437,
+ T1_2512_2732
+};
+
+static struct regDomain regDomains[] = {
+
+ {DEBUG_REG_DMN, FCC, DFS_FCC3, NO_PSCAN, NO_REQ,
+ BM(A_DEMO_ALL_CHANNELS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_5130_5650, T1_5150_5670, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_5200_5240, T1_5280_5280, T1_5540_5660, T1_5765_5805, -1, -1,
+ -1, -1, -1, -1, -1, -1),
+ BM(F1_2312_2372, F1_2412_2472, F1_2484_2484, F1_2512_2732, -1, -1,
+ -1, -1, -1, -1, -1, -1),
+ BM(G_DEMO_ALL_CHANNELS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_2312_2372, T1_2437_2437, T1_2512_2732, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1)},
+
+ {APL1, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F4_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL2, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F1_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL3, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F1_5280_5320, F2_5745_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_5290_5290, T1_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL4, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F4_5180_5240, F3_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_5210_5210, T3_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_5200_5200, T3_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL5, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F2_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T4_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T4_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL6, ETSI, DFS_ETSI, PSCAN_FCC_T | PSCAN_FCC, NO_REQ,
+ BM(F4_5180_5240, F2_5260_5320, F3_5745_5825, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T2_5210_5210, T1_5250_5290, T1_5760_5800, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T1_5200_5280, T5_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL7, ETSI, DFS_ETSI, PSCAN_ETSI, NO_REQ,
+ BM(F1_5280_5320, F5_5500_5700, F3_5745_5805, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T3_5290_5290, T5_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_5540_5660, T6_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL8, ETSI, NO_DFS, NO_PSCAN,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F6_5260_5320, F4_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T2_5290_5290, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_5280_5280, T1_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL9, ETSI, DFS_ETSI, PSCAN_ETSI,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5180_5320, F1_5500_5620, F3_5745_5805, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T3_5290_5290, T5_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_5540_5660, T6_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {APL10, ETSI, DFS_ETSI, PSCAN_ETSI,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5180_5320, F5_5500_5700, F3_5745_5805, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T3_5290_5290, T5_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_5540_5660, T6_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI1, ETSI, DFS_ETSI, PSCAN_ETSI,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F4_5180_5240, F2_5260_5320, F2_5500_5700, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T1_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_5200_5280, T2_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI2, ETSI, DFS_ETSI, PSCAN_ETSI,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F3_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T3_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI3, ETSI, DFS_ETSI, PSCAN_ETSI,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T1_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI4, ETSI, DFS_ETSI, PSCAN_ETSI,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F3_5180_5240, F1_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T2_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T3_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI5, ETSI, DFS_ETSI, PSCAN_ETSI,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T4_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T3_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {ETSI6, ETSI, DFS_ETSI, PSCAN_ETSI,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F5_5180_5240, F1_5260_5280, F3_5500_5700, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T1_5210_5250, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T4_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {FCC1, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F2_5180_5240, F4_5260_5320, F5_5745_5825, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T6_5210_5210, T2_5250_5290, T6_5760_5800, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T1_5200_5240, T2_5280_5280, T7_5765_5805, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {FCC2, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F6_5180_5240, F5_5260_5320, F6_5745_5825, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T7_5210_5210, T3_5250_5290, T2_5760_5800, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T7_5200_5200, T1_5240_5240, T2_5280_5280, T1_5765_5805, -1, -1,
+ -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {FCC3, FCC, DFS_FCC3, PSCAN_FCC | PSCAN_FCC_T, NO_REQ,
+ BM(F2_5180_5240, F3_5260_5320, F1_5500_5700, F5_5745_5825, -1, -1,
+ -1, -1, -1, -1, -1, -1),
+ BM(T6_5210_5210, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T4_5200_5200, T8_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {FCC4, FCC, DFS_FCC3, PSCAN_FCC | PSCAN_FCC_T, NO_REQ,
+ BM(F1_4942_4987, F1_4945_4985, F1_4950_4980, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T8_5210_5210, T4_5250_5290, T7_5760_5800, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T1_5200_5240, T1_5280_5280, T9_5765_5805, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {FCC5, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BM(F2_5180_5240, F6_5745_5825, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T6_5210_5210, T2_5760_5800, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T8_5200_5200, T7_5765_5805, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {FCC6, FCC, DFS_FCC3, PSCAN_FCC, NO_REQ,
+ BM(F8_5180_5240, F5_5260_5320, F1_5500_5580, F1_5660_5700,
+ F6_5745_5825, -1, -1, -1, -1, -1, -1, -1),
+ BM(T7_5210_5210, T3_5250_5290, T2_5760_5800, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T7_5200_5200, T1_5240_5240, T2_5280_5280, T1_5765_5805, -1, -1,
+ -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {MKK1, MKK, NO_DFS, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5170_5230, F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1,
+ -1, -1, -1, -1, -1, -1),
+ BM(T7_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T5_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+ {MKK2, MKK, NO_DFS, PSCAN_MKK2, DISALLOW_ADHOC_11A_TURB,
+ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040,
+ F1_5055_5055, F1_5040_5080, F1_5170_5230, F4_5180_5240,
+ F2_5260_5320, F4_5500_5700, -1, -1),
+ BM(T7_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T5_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK3, MKK, NO_DFS, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB,
+ BM(F4_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T9_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK4, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB,
+ BM(F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T10_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T6_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK5, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB,
+ BM(F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T5_5200_5280, T3_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK6, MKK, NO_DFS, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB,
+ BM(F2_5170_5230, F4_5180_5240, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T3_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T6_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK7, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3,
+ DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5170_5230, F4_5180_5240, F2_5260_5320, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T5_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK8, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3,
+ DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5170_5230, F4_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1,
+ -1, -1, -1, -1, -1, -1),
+ BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T5_5200_5280, T3_5540_5660, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK9, MKK, NO_DFS, PSCAN_MKK2 | PSCAN_MKK3,
+ DISALLOW_ADHOC_11A_TURB,
+ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040,
+ F1_5055_5055, F1_5040_5080, F4_5180_5240, -1, -1, -1, -1, -1),
+ BM(T9_5210_5210, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5200_5200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK10, MKK, DFS_MKK4, PSCAN_MKK2 | PSCAN_MKK3,
+ DISALLOW_ADHOC_11A_TURB,
+ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040,
+ F1_5055_5055, F1_5040_5080, F4_5180_5240, F2_5260_5320, -1, -1,
+ -1, -1),
+ BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK11, MKK, DFS_MKK4, PSCAN_MKK3, DISALLOW_ADHOC_11A_TURB,
+ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040,
+ F1_5055_5055, F1_5040_5080, F4_5180_5240, F2_5260_5320,
+ F4_5500_5700, -1, -1, -1),
+ BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK12, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3,
+ DISALLOW_ADHOC_11A_TURB,
+ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040,
+ F1_5055_5055, F1_5040_5080, F1_5170_5230, F4_5180_5240,
+ F2_5260_5320, F4_5500_5700, -1, -1),
+ BM(T3_5210_5290, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T1_5200_5280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK13, MKK, DFS_MKK4, PSCAN_MKK1 | PSCAN_MKK3,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BM(F1_5170_5230, F7_5180_5240, F2_5260_5320, F4_5500_5700, -1, -1,
+ -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK14, MKK, DFS_MKK4, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB,
+ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040,
+ F1_5040_5080, F1_5055_5055, F1_5170_5230, F4_5180_5240, -1, -1,
+ -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {MKK15, MKK, DFS_MKK4, PSCAN_MKK1, DISALLOW_ADHOC_11A_TURB,
+ BM(F1_4915_4925, F1_4935_4945, F1_4920_4980, F1_5035_5040,
+ F1_5040_5080, F1_5055_5055, F1_5170_5230, F4_5180_5240,
+ F2_5260_5320, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO},
+
+
+ {APLD, NO_CTL, NO_DFS, NO_PSCAN, NO_REQ,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F2_2312_2372, F2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(G2_2312_2372, G2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BMZERO},
+
+ {ETSIA, NO_CTL, NO_DFS, PSCAN_ETSIA,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F1_2457_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(G1_2457_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {ETSIB, ETSI, NO_DFS, PSCAN_ETSIB,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F1_2432_2442, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(G1_2432_2442, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {ETSIC, ETSI, NO_DFS, PSCAN_ETSIC,
+ DISALLOW_ADHOC_11A | DISALLOW_ADHOC_11A_TURB,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F3_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(G3_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {FCCA, FCC, NO_DFS, NO_PSCAN, NO_REQ,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(G1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {MKKA, MKK, NO_DFS,
+ PSCAN_MKKA | PSCAN_MKKA_G | PSCAN_MKKA1 | PSCAN_MKKA1_G |
+ PSCAN_MKKA2 | PSCAN_MKKA2_G, DISALLOW_ADHOC_11A_TURB,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F2_2412_2462, F1_2467_2472, F2_2484_2484, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(G2_2412_2462, G1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1),
+ BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {MKKC, MKK, NO_DFS, NO_PSCAN, NO_REQ,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(G2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WORLD, ETSI, NO_DFS, NO_PSCAN, NO_REQ,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BM(F2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(G2_2412_2472, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T2_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR0_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825,
+ W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472,
+ W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1,
+ -1, -1),
+ BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR01_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR,
+ ADHOC_PER_11D,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825,
+ W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432,
+ W1_2447_2457, -1, -1, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR02_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR,
+ ADHOC_PER_11D,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825,
+ W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472,
+ W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {EU1_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825,
+ W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W2_2472_2472,
+ W1_2417_2432, W1_2447_2457, W2_2467_2467, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2462, WG2_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR1_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825,
+ W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472,
+ W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1,
+ -1, -1),
+ BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR2_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825,
+ W1_5500_5700, -1, -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472,
+ W1_2417_2432, W1_2447_2457, W1_2467_2467, W1_2484_2484, -1, -1,
+ -1, -1),
+ BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR3_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_PER_11D,
+ BM(W1_5260_5320, W1_5180_5240, W1_5170_5230, W1_5745_5825, -1, -1,
+ -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472,
+ W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2462, WG2_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR4_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432,
+ W1_2447_2457, -1, -1, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR5_ETSIC, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472,
+ W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WOR9_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, W1_5500_5700, -1, -1,
+ -1, -1, -1, -1, -1, -1),
+ BM(WT1_5210_5250, WT1_5290_5290, WT1_5760_5800, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1),
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2417_2432,
+ W1_2447_2457, -1, -1, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2462, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WORA_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W1_5180_5240, W1_5745_5825, W1_5500_5700, -1, -1,
+ -1, -1, -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472,
+ W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {WORB_WORLD, NO_CTL, DFS_FCC3 | DFS_ETSI, PSCAN_WWR, ADHOC_NO_11A,
+ BM(W1_5260_5320, W1_5180_5240, W1_5500_5700, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1),
+ BMZERO,
+ BMZERO,
+ BM(W1_2412_2412, W1_2437_2442, W1_2462_2462, W1_2472_2472,
+ W1_2417_2432, W1_2447_2457, W1_2467_2467, -1, -1, -1, -1, -1),
+ BM(WG1_2412_2462, WG1_2467_2472, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1),
+ BM(T3_2437_2437, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)},
+
+ {NULL1, NO_CTL, NO_DFS, NO_PSCAN, NO_REQ,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO,
+ BMZERO}
+};
+
+static const struct cmode modes[] = {
+ {ATH9K_MODE_11A, CHANNEL_A},
+ {ATH9K_MODE_11B, CHANNEL_B},
+ {ATH9K_MODE_11G, CHANNEL_G},
+ {ATH9K_MODE_11NG_HT20, CHANNEL_G_HT20},
+ {ATH9K_MODE_11NG_HT40PLUS, CHANNEL_G_HT40PLUS},
+ {ATH9K_MODE_11NG_HT40MINUS, CHANNEL_G_HT40MINUS},
+ {ATH9K_MODE_11NA_HT20, CHANNEL_A_HT20},
+ {ATH9K_MODE_11NA_HT40PLUS, CHANNEL_A_HT40PLUS},
+ {ATH9K_MODE_11NA_HT40MINUS, CHANNEL_A_HT40MINUS},
+};
+
+static struct japan_bandcheck j_bandcheck[] = {
+ {F1_5170_5230, AR_EEPROM_EEREGCAP_EN_KK_U1_ODD},
+ {F4_5180_5240, AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN},
+ {F2_5260_5320, AR_EEPROM_EEREGCAP_EN_KK_U2},
+ {F4_5500_5700, AR_EEPROM_EEREGCAP_EN_KK_MIDBAND}
+};
+
+
+#endif
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
new file mode 100644
index 00000000000..550129f717e
--- /dev/null
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -0,0 +1,2871 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Implementation of transmit path.
+ */
+
+#include "core.h"
+
+#define BITS_PER_BYTE 8
+#define OFDM_PLCP_BITS 22
+#define HT_RC_2_MCS(_rc) ((_rc) & 0x0f)
+#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
+#define L_STF 8
+#define L_LTF 8
+#define L_SIG 4
+#define HT_SIG 8
+#define HT_STF 4
+#define HT_LTF(_ns) (4 * (_ns))
+#define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */
+#define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */
+#define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2)
+#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18)
+
+#define OFDM_SIFS_TIME 16
+
+static u32 bits_per_symbol[][2] = {
+ /* 20MHz 40MHz */
+ { 26, 54 }, /* 0: BPSK */
+ { 52, 108 }, /* 1: QPSK 1/2 */
+ { 78, 162 }, /* 2: QPSK 3/4 */
+ { 104, 216 }, /* 3: 16-QAM 1/2 */
+ { 156, 324 }, /* 4: 16-QAM 3/4 */
+ { 208, 432 }, /* 5: 64-QAM 2/3 */
+ { 234, 486 }, /* 6: 64-QAM 3/4 */
+ { 260, 540 }, /* 7: 64-QAM 5/6 */
+ { 52, 108 }, /* 8: BPSK */
+ { 104, 216 }, /* 9: QPSK 1/2 */
+ { 156, 324 }, /* 10: QPSK 3/4 */
+ { 208, 432 }, /* 11: 16-QAM 1/2 */
+ { 312, 648 }, /* 12: 16-QAM 3/4 */
+ { 416, 864 }, /* 13: 64-QAM 2/3 */
+ { 468, 972 }, /* 14: 64-QAM 3/4 */
+ { 520, 1080 }, /* 15: 64-QAM 5/6 */
+};
+
+#define IS_HT_RATE(_rate) ((_rate) & 0x80)
+
+/*
+ * Insert a chain of ath_buf (descriptors) on a multicast txq
+ * but do NOT start tx DMA on this queue.
+ * NB: must be called with txq lock held
+ */
+
+static void ath_tx_mcastqaddbuf(struct ath_softc *sc,
+ struct ath_txq *txq,
+ struct list_head *head)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf;
+
+ if (list_empty(head))
+ return;
+
+ /*
+ * Insert the frame on the outbound list and
+ * pass it on to the hardware.
+ */
+ bf = list_first_entry(head, struct ath_buf, list);
+
+ /*
+ * The CAB queue is started from the SWBA handler since
+ * frames only go out on DTIM and to avoid possible races.
+ */
+ ath9k_hw_set_interrupts(ah, 0);
+
+ /*
+ * If there is anything in the mcastq, we want to set
+ * the "more data" bit in the last item in the queue to
+ * indicate that there is "more data". It makes sense to add
+ * it here since you are *always* going to have
+ * more data when adding to this queue, no matter where
+ * you call from.
+ */
+
+ if (txq->axq_depth) {
+ struct ath_buf *lbf;
+ struct ieee80211_hdr *hdr;
+
+ /*
+ * Add the "more data flag" to the last frame
+ */
+
+ lbf = list_entry(txq->axq_q.prev, struct ath_buf, list);
+ hdr = (struct ieee80211_hdr *)
+ ((struct sk_buff *)(lbf->bf_mpdu))->data;
+ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+ }
+
+ /*
+ * Now, concat the frame onto the queue
+ */
+ list_splice_tail_init(head, &txq->axq_q);
+ txq->axq_depth++;
+ txq->axq_totalqueued++;
+ txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
+
+ DPRINTF(sc, ATH_DBG_QUEUE,
+ "%s: txq depth = %d\n", __func__, txq->axq_depth);
+ if (txq->axq_link != NULL) {
+ *txq->axq_link = bf->bf_daddr;
+ DPRINTF(sc, ATH_DBG_XMIT,
+ "%s: link[%u](%p)=%llx (%p)\n",
+ __func__,
+ txq->axq_qnum, txq->axq_link,
+ ito64(bf->bf_daddr), bf->bf_desc);
+ }
+ txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link);
+ ath9k_hw_set_interrupts(ah, sc->sc_imask);
+}
+
+/*
+ * Insert a chain of ath_buf (descriptors) on a txq and
+ * assume the descriptors are already chained together by caller.
+ * NB: must be called with txq lock held
+ */
+
+static void ath_tx_txqaddbuf(struct ath_softc *sc,
+ struct ath_txq *txq, struct list_head *head)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf;
+ /*
+ * Insert the frame on the outbound list and
+ * pass it on to the hardware.
+ */
+
+ if (list_empty(head))
+ return;
+
+ bf = list_first_entry(head, struct ath_buf, list);
+
+ list_splice_tail_init(head, &txq->axq_q);
+ txq->axq_depth++;
+ txq->axq_totalqueued++;
+ txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
+
+ DPRINTF(sc, ATH_DBG_QUEUE,
+ "%s: txq depth = %d\n", __func__, txq->axq_depth);
+
+ if (txq->axq_link == NULL) {
+ ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
+ DPRINTF(sc, ATH_DBG_XMIT,
+ "%s: TXDP[%u] = %llx (%p)\n",
+ __func__, txq->axq_qnum,
+ ito64(bf->bf_daddr), bf->bf_desc);
+ } else {
+ *txq->axq_link = bf->bf_daddr;
+ DPRINTF(sc, ATH_DBG_XMIT, "%s: link[%u] (%p)=%llx (%p)\n",
+ __func__,
+ txq->axq_qnum, txq->axq_link,
+ ito64(bf->bf_daddr), bf->bf_desc);
+ }
+ txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link);
+ ath9k_hw_txstart(ah, txq->axq_qnum);
+}
+
+/* Get transmit rate index using rate in Kbps */
+
+static int ath_tx_findindex(const struct ath9k_rate_table *rt, int rate)
+{
+ int i;
+ int ndx = 0;
+
+ for (i = 0; i < rt->rateCount; i++) {
+ if (rt->info[i].rateKbps == rate) {
+ ndx = i;
+ break;
+ }
+ }
+
+ return ndx;
+}
+
+/* Check if it's okay to send out aggregates */
+
+static int ath_aggr_query(struct ath_softc *sc,
+ struct ath_node *an, u8 tidno)
+{
+ struct ath_atx_tid *tid;
+ tid = ATH_AN_2_TID(an, tidno);
+
+ if (tid->addba_exchangecomplete || tid->addba_exchangeinprogress)
+ return 1;
+ else
+ return 0;
+}
+
+static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr)
+{
+ enum ath9k_pkt_type htype;
+ __le16 fc;
+
+ fc = hdr->frame_control;
+
+ /* Calculate Atheros packet type from IEEE80211 packet header */
+
+ if (ieee80211_is_beacon(fc))
+ htype = ATH9K_PKT_TYPE_BEACON;
+ else if (ieee80211_is_probe_resp(fc))
+ htype = ATH9K_PKT_TYPE_PROBE_RESP;
+ else if (ieee80211_is_atim(fc))
+ htype = ATH9K_PKT_TYPE_ATIM;
+ else if (ieee80211_is_pspoll(fc))
+ htype = ATH9K_PKT_TYPE_PSPOLL;
+ else
+ htype = ATH9K_PKT_TYPE_NORMAL;
+
+ return htype;
+}
+
+static void fill_min_rates(struct sk_buff *skb, struct ath_tx_control *txctl)
+{
+ struct ieee80211_hdr *hdr;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ath_tx_info_priv *tx_info_priv;
+ __le16 fc;
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = hdr->frame_control;
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
+ txctl->use_minrate = 1;
+ txctl->min_rate = tx_info_priv->min_rate;
+ } else if (ieee80211_is_data(fc)) {
+ if (ieee80211_is_nullfunc(fc) ||
+ /* Port Access Entity (IEEE 802.1X) */
+ (skb->protocol == cpu_to_be16(0x888E))) {
+ txctl->use_minrate = 1;
+ txctl->min_rate = tx_info_priv->min_rate;
+ }
+ if (is_multicast_ether_addr(hdr->addr1))
+ txctl->mcast_rate = tx_info_priv->min_rate;
+ }
+
+}
+
+/* This function will setup additional txctl information, mostly rate stuff */
+/* FIXME: seqno, ps */
+static int ath_tx_prepare(struct ath_softc *sc,
+ struct sk_buff *skb,
+ struct ath_tx_control *txctl)
+{
+ struct ieee80211_hw *hw = sc->hw;
+ struct ieee80211_hdr *hdr;
+ struct ath_rc_series *rcs;
+ struct ath_txq *txq = NULL;
+ const struct ath9k_rate_table *rt;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ath_tx_info_priv *tx_info_priv;
+ int hdrlen;
+ u8 rix, antenna;
+ __le16 fc;
+ u8 *qc;
+
+ memset(txctl, 0, sizeof(struct ath_tx_control));
+
+ txctl->dev = sc;
+ hdr = (struct ieee80211_hdr *)skb->data;
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ fc = hdr->frame_control;
+
+ rt = sc->sc_currates;
+ BUG_ON(!rt);
+
+ /* Fill misc fields */
+
+ spin_lock_bh(&sc->node_lock);
+ txctl->an = ath_node_get(sc, hdr->addr1);
+ /* create a temp node, if the node is not there already */
+ if (!txctl->an)
+ txctl->an = ath_node_attach(sc, hdr->addr1, 0);
+ spin_unlock_bh(&sc->node_lock);
+
+ if (ieee80211_is_data_qos(fc)) {
+ qc = ieee80211_get_qos_ctl(hdr);
+ txctl->tidno = qc[0] & 0xf;
+ }
+
+ txctl->if_id = 0;
+ txctl->nextfraglen = 0;
+ txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3);
+ txctl->txpower = MAX_RATE_POWER; /* FIXME */
+
+ /* Fill Key related fields */
+
+ txctl->keytype = ATH9K_KEY_TYPE_CLEAR;
+ txctl->keyix = ATH9K_TXKEYIX_INVALID;
+
+ if (tx_info->control.hw_key) {
+ txctl->keyix = tx_info->control.hw_key->hw_key_idx;
+ txctl->frmlen += tx_info->control.icv_len;
+
+ if (sc->sc_keytype == ATH9K_CIPHER_WEP)
+ txctl->keytype = ATH9K_KEY_TYPE_WEP;
+ else if (sc->sc_keytype == ATH9K_CIPHER_TKIP)
+ txctl->keytype = ATH9K_KEY_TYPE_TKIP;
+ else if (sc->sc_keytype == ATH9K_CIPHER_AES_CCM)
+ txctl->keytype = ATH9K_KEY_TYPE_AES;
+ }
+
+ /* Fill packet type */
+
+ txctl->atype = get_hal_packet_type(hdr);
+
+ /* Fill qnum */
+
+ txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
+ txq = &sc->sc_txq[txctl->qnum];
+ spin_lock_bh(&txq->axq_lock);
+
+ /* Try to avoid running out of descriptors */
+ if (txq->axq_depth >= (ATH_TXBUF - 20)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: TX queue: %d is full, depth: %d\n",
+ __func__,
+ txctl->qnum,
+ txq->axq_depth);
+ ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
+ txq->stopped = 1;
+ spin_unlock_bh(&txq->axq_lock);
+ return -1;
+ }
+
+ spin_unlock_bh(&txq->axq_lock);
+
+ /* Fill rate */
+
+ fill_min_rates(skb, txctl);
+
+ /* Fill flags */
+
+ txctl->flags = ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
+
+ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
+ txctl->flags |= ATH9K_TXDESC_NOACK;
+ if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+ txctl->flags |= ATH9K_TXDESC_RTSENA;
+
+ /*
+ * Setup for rate calculations.
+ */
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+ rcs = tx_info_priv->rcs;
+
+ if (ieee80211_is_data(fc) && !txctl->use_minrate) {
+
+ /* Enable HT only for DATA frames and not for EAPOL */
+ txctl->ht = (hw->conf.ht_conf.ht_supported &&
+ (tx_info->flags & IEEE80211_TX_CTL_AMPDU));
+
+ if (is_multicast_ether_addr(hdr->addr1)) {
+ rcs[0].rix = (u8)
+ ath_tx_findindex(rt, txctl->mcast_rate);
+
+ /*
+ * mcast packets are not re-tried.
+ */
+ rcs[0].tries = 1;
+ }
+ /* For HT capable stations, we save tidno for later use.
+ * We also override seqno set by upper layer with the one
+ * in tx aggregation state.
+ *
+ * First, the fragmentation stat is determined.
+ * If fragmentation is on, the sequence number is
+ * not overridden, since it has been
+ * incremented by the fragmentation routine.
+ */
+ if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) &&
+ txctl->ht && sc->sc_txaggr) {
+ struct ath_atx_tid *tid;
+
+ tid = ATH_AN_2_TID(txctl->an, txctl->tidno);
+
+ hdr->seq_ctrl = cpu_to_le16(tid->seq_next <<
+ IEEE80211_SEQ_SEQ_SHIFT);
+ txctl->seqno = tid->seq_next;
+ INCR(tid->seq_next, IEEE80211_SEQ_MAX);
+ }
+ } else {
+ /* for management and control frames,
+ * or for NULL and EAPOL frames */
+ if (txctl->min_rate)
+ rcs[0].rix = ath_rate_findrateix(sc, txctl->min_rate);
+ else
+ rcs[0].rix = 0;
+ rcs[0].tries = ATH_MGT_TXMAXTRY;
+ }
+ rix = rcs[0].rix;
+
+ /*
+ * Calculate duration. This logically belongs in the 802.11
+ * layer but it lacks sufficient information to calculate it.
+ */
+ if ((txctl->flags & ATH9K_TXDESC_NOACK) == 0 && !ieee80211_is_ctl(fc)) {
+ u16 dur;
+ /*
+ * XXX not right with fragmentation.
+ */
+ if (sc->sc_flags & ATH_PREAMBLE_SHORT)
+ dur = rt->info[rix].spAckDuration;
+ else
+ dur = rt->info[rix].lpAckDuration;
+
+ if (le16_to_cpu(hdr->frame_control) &
+ IEEE80211_FCTL_MOREFRAGS) {
+ dur += dur; /* Add additional 'SIFS + ACK' */
+
+ /*
+ ** Compute size of next fragment in order to compute
+ ** durations needed to update NAV.
+ ** The last fragment uses the ACK duration only.
+ ** Add time for next fragment.
+ */
+ dur += ath9k_hw_computetxtime(sc->sc_ah, rt,
+ txctl->nextfraglen,
+ rix, sc->sc_flags & ATH_PREAMBLE_SHORT);
+ }
+
+ if (ieee80211_has_morefrags(fc) ||
+ (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
+ /*
+ ** Force hardware to use computed duration for next
+ ** fragment by disabling multi-rate retry, which
+ ** updates duration based on the multi-rate
+ ** duration table.
+ */
+ rcs[1].tries = rcs[2].tries = rcs[3].tries = 0;
+ rcs[1].rix = rcs[2].rix = rcs[3].rix = 0;
+ /* reset tries but keep rate index */
+ rcs[0].tries = ATH_TXMAXTRY;
+ }
+
+ hdr->duration_id = cpu_to_le16(dur);
+ }
+
+ /*
+ * Determine if a tx interrupt should be generated for
+ * this descriptor. We take a tx interrupt to reap
+ * descriptors when the h/w hits an EOL condition or
+ * when the descriptor is specifically marked to generate
+ * an interrupt. We periodically mark descriptors in this
+ * way to insure timely replenishing of the supply needed
+ * for sending frames. Defering interrupts reduces system
+ * load and potentially allows more concurrent work to be
+ * done but if done to aggressively can cause senders to
+ * backup.
+ *
+ * NB: use >= to deal with sc_txintrperiod changing
+ * dynamically through sysctl.
+ */
+ spin_lock_bh(&txq->axq_lock);
+ if ((++txq->axq_intrcnt >= sc->sc_txintrperiod)) {
+ txctl->flags |= ATH9K_TXDESC_INTREQ;
+ txq->axq_intrcnt = 0;
+ }
+ spin_unlock_bh(&txq->axq_lock);
+
+ if (is_multicast_ether_addr(hdr->addr1)) {
+ antenna = sc->sc_mcastantenna + 1;
+ sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1;
+ } else
+ antenna = sc->sc_txantenna;
+
+#ifdef USE_LEGACY_HAL
+ txctl->antenna = antenna;
+#endif
+ return 0;
+}
+
+/* To complete a chain of buffers associated a frame */
+
+static void ath_tx_complete_buf(struct ath_softc *sc,
+ struct ath_buf *bf,
+ struct list_head *bf_q,
+ int txok, int sendbar)
+{
+ struct sk_buff *skb = bf->bf_mpdu;
+ struct ath_xmit_status tx_status;
+ dma_addr_t *pa;
+
+ /*
+ * Set retry information.
+ * NB: Don't use the information in the descriptor, because the frame
+ * could be software retried.
+ */
+ tx_status.retries = bf->bf_retries;
+ tx_status.flags = 0;
+
+ if (sendbar)
+ tx_status.flags = ATH_TX_BAR;
+
+ if (!txok) {
+ tx_status.flags |= ATH_TX_ERROR;
+
+ if (bf->bf_isxretried)
+ tx_status.flags |= ATH_TX_XRETRY;
+ }
+ /* Unmap this frame */
+ pa = get_dma_mem_context(bf, bf_dmacontext);
+ pci_unmap_single(sc->pdev,
+ *pa,
+ skb->len,
+ PCI_DMA_TODEVICE);
+ /* complete this frame */
+ ath_tx_complete(sc, skb, &tx_status, bf->bf_node);
+
+ /*
+ * Return the list of ath_buf of this mpdu to free queue
+ */
+ spin_lock_bh(&sc->sc_txbuflock);
+ list_splice_tail_init(bf_q, &sc->sc_txbuf);
+ spin_unlock_bh(&sc->sc_txbuflock);
+}
+
+/*
+ * queue up a dest/ac pair for tx scheduling
+ * NB: must be called with txq lock held
+ */
+
+static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
+{
+ struct ath_atx_ac *ac = tid->ac;
+
+ /*
+ * if tid is paused, hold off
+ */
+ if (tid->paused)
+ return;
+
+ /*
+ * add tid to ac atmost once
+ */
+ if (tid->sched)
+ return;
+
+ tid->sched = true;
+ list_add_tail(&tid->list, &ac->tid_q);
+
+ /*
+ * add node ac to txq atmost once
+ */
+ if (ac->sched)
+ return;
+
+ ac->sched = true;
+ list_add_tail(&ac->list, &txq->axq_acq);
+}
+
+/* pause a tid */
+
+static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
+{
+ struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum];
+
+ spin_lock_bh(&txq->axq_lock);
+
+ tid->paused++;
+
+ spin_unlock_bh(&txq->axq_lock);
+}
+
+/* resume a tid and schedule aggregate */
+
+void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
+{
+ struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum];
+
+ ASSERT(tid->paused > 0);
+ spin_lock_bh(&txq->axq_lock);
+
+ tid->paused--;
+
+ if (tid->paused > 0)
+ goto unlock;
+
+ if (list_empty(&tid->buf_q))
+ goto unlock;
+
+ /*
+ * Add this TID to scheduler and try to send out aggregates
+ */
+ ath_tx_queue_tid(txq, tid);
+ ath_txq_schedule(sc, txq);
+unlock:
+ spin_unlock_bh(&txq->axq_lock);
+}
+
+/* Compute the number of bad frames */
+
+static int ath_tx_num_badfrms(struct ath_softc *sc,
+ struct ath_buf *bf, int txok)
+{
+ struct ath_node *an = bf->bf_node;
+ int isnodegone = (an->an_flags & ATH_NODE_CLEAN);
+ struct ath_buf *bf_last = bf->bf_lastbf;
+ struct ath_desc *ds = bf_last->bf_desc;
+ u16 seq_st = 0;
+ u32 ba[WME_BA_BMP_SIZE >> 5];
+ int ba_index;
+ int nbad = 0;
+ int isaggr = 0;
+
+ if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED)
+ return 0;
+
+ isaggr = bf->bf_isaggr;
+ if (isaggr) {
+ seq_st = ATH_DS_BA_SEQ(ds);
+ memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3);
+ }
+
+ while (bf) {
+ ba_index = ATH_BA_INDEX(seq_st, bf->bf_seqno);
+ if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
+ nbad++;
+
+ bf = bf->bf_next;
+ }
+
+ return nbad;
+}
+
+static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct sk_buff *skb;
+ struct ieee80211_hdr *hdr;
+
+ bf->bf_isretried = 1;
+ bf->bf_retries++;
+
+ skb = bf->bf_mpdu;
+ hdr = (struct ieee80211_hdr *)skb->data;
+ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
+}
+
+/* Update block ack window */
+
+static void ath_tx_update_baw(struct ath_softc *sc,
+ struct ath_atx_tid *tid, int seqno)
+{
+ int index, cindex;
+
+ index = ATH_BA_INDEX(tid->seq_start, seqno);
+ cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
+
+ tid->tx_buf[cindex] = NULL;
+
+ while (tid->baw_head != tid->baw_tail && !tid->tx_buf[tid->baw_head]) {
+ INCR(tid->seq_start, IEEE80211_SEQ_MAX);
+ INCR(tid->baw_head, ATH_TID_MAX_BUFS);
+ }
+}
+
+/*
+ * ath_pkt_dur - compute packet duration (NB: not NAV)
+ *
+ * rix - rate index
+ * pktlen - total bytes (delims + data + fcs + pads + pad delims)
+ * width - 0 for 20 MHz, 1 for 40 MHz
+ * half_gi - to use 4us v/s 3.6 us for symbol time
+ */
+
+static u32 ath_pkt_duration(struct ath_softc *sc,
+ u8 rix,
+ struct ath_buf *bf,
+ int width,
+ int half_gi,
+ bool shortPreamble)
+{
+ const struct ath9k_rate_table *rt = sc->sc_currates;
+ u32 nbits, nsymbits, duration, nsymbols;
+ u8 rc;
+ int streams, pktlen;
+
+ pktlen = bf->bf_isaggr ? bf->bf_al : bf->bf_frmlen;
+ rc = rt->info[rix].rateCode;
+
+ /*
+ * for legacy rates, use old function to compute packet duration
+ */
+ if (!IS_HT_RATE(rc))
+ return ath9k_hw_computetxtime(sc->sc_ah,
+ rt,
+ pktlen,
+ rix,
+ shortPreamble);
+ /*
+ * find number of symbols: PLCP + data
+ */
+ nbits = (pktlen << 3) + OFDM_PLCP_BITS;
+ nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
+ nsymbols = (nbits + nsymbits - 1) / nsymbits;
+
+ if (!half_gi)
+ duration = SYMBOL_TIME(nsymbols);
+ else
+ duration = SYMBOL_TIME_HALFGI(nsymbols);
+
+ /*
+ * addup duration for legacy/ht training and signal fields
+ */
+ streams = HT_RC_2_STREAMS(rc);
+ duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
+ return duration;
+}
+
+/* Rate module function to set rate related fields in tx descriptor */
+
+static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ const struct ath9k_rate_table *rt;
+ struct ath_desc *ds = bf->bf_desc;
+ struct ath_desc *lastds = bf->bf_lastbf->bf_desc;
+ struct ath9k_11n_rate_series series[4];
+ int i, flags, rtsctsena = 0, dynamic_mimops = 0;
+ u32 ctsduration = 0;
+ u8 rix = 0, cix, ctsrate = 0;
+ u32 aggr_limit_with_rts = sc->sc_rtsaggrlimit;
+ struct ath_node *an = (struct ath_node *) bf->bf_node;
+
+ /*
+ * get the cix for the lowest valid rix.
+ */
+ rt = sc->sc_currates;
+ for (i = 4; i--;) {
+ if (bf->bf_rcs[i].tries) {
+ rix = bf->bf_rcs[i].rix;
+ break;
+ }
+ }
+ flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA));
+ cix = rt->info[rix].controlRate;
+
+ /*
+ * If 802.11g protection is enabled, determine whether
+ * to use RTS/CTS or just CTS. Note that this is only
+ * done for OFDM/HT unicast frames.
+ */
+ if (sc->sc_protmode != PROT_M_NONE &&
+ (rt->info[rix].phy == PHY_OFDM ||
+ rt->info[rix].phy == PHY_HT) &&
+ (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
+ if (sc->sc_protmode == PROT_M_RTSCTS)
+ flags = ATH9K_TXDESC_RTSENA;
+ else if (sc->sc_protmode == PROT_M_CTSONLY)
+ flags = ATH9K_TXDESC_CTSENA;
+
+ cix = rt->info[sc->sc_protrix].controlRate;
+ rtsctsena = 1;
+ }
+
+ /* For 11n, the default behavior is to enable RTS for
+ * hw retried frames. We enable the global flag here and
+ * let rate series flags determine which rates will actually
+ * use RTS.
+ */
+ if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf->bf_isdata) {
+ BUG_ON(!an);
+ /*
+ * 802.11g protection not needed, use our default behavior
+ */
+ if (!rtsctsena)
+ flags = ATH9K_TXDESC_RTSENA;
+ /*
+ * For dynamic MIMO PS, RTS needs to precede the first aggregate
+ * and the second aggregate should have any protection at all.
+ */
+ if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) {
+ if (!bf->bf_aggrburst) {
+ flags = ATH9K_TXDESC_RTSENA;
+ dynamic_mimops = 1;
+ } else {
+ flags = 0;
+ }
+ }
+ }
+
+ /*
+ * Set protection if aggregate protection on
+ */
+ if (sc->sc_config.ath_aggr_prot &&
+ (!bf->bf_isaggr || (bf->bf_isaggr && bf->bf_al < 8192))) {
+ flags = ATH9K_TXDESC_RTSENA;
+ cix = rt->info[sc->sc_protrix].controlRate;
+ rtsctsena = 1;
+ }
+
+ /*
+ * For AR5416 - RTS cannot be followed by a frame larger than 8K.
+ */
+ if (bf->bf_isaggr && (bf->bf_al > aggr_limit_with_rts)) {
+ /*
+ * Ensure that in the case of SM Dynamic power save
+ * while we are bursting the second aggregate the
+ * RTS is cleared.
+ */
+ flags &= ~(ATH9K_TXDESC_RTSENA);
+ }
+
+ /*
+ * CTS transmit rate is derived from the transmit rate
+ * by looking in the h/w rate table. We must also factor
+ * in whether or not a short preamble is to be used.
+ */
+ /* NB: cix is set above where RTS/CTS is enabled */
+ BUG_ON(cix == 0xff);
+ ctsrate = rt->info[cix].rateCode |
+ (bf->bf_shpreamble ? rt->info[cix].shortPreamble : 0);
+
+ /*
+ * Setup HAL rate series
+ */
+ memzero(series, sizeof(struct ath9k_11n_rate_series) * 4);
+
+ for (i = 0; i < 4; i++) {
+ if (!bf->bf_rcs[i].tries)
+ continue;
+
+ rix = bf->bf_rcs[i].rix;
+
+ series[i].Rate = rt->info[rix].rateCode |
+ (bf->bf_shpreamble ? rt->info[rix].shortPreamble : 0);
+
+ series[i].Tries = bf->bf_rcs[i].tries;
+
+ series[i].RateFlags = (
+ (bf->bf_rcs[i].flags & ATH_RC_RTSCTS_FLAG) ?
+ ATH9K_RATESERIES_RTS_CTS : 0) |
+ ((bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) ?
+ ATH9K_RATESERIES_2040 : 0) |
+ ((bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG) ?
+ ATH9K_RATESERIES_HALFGI : 0);
+
+ series[i].PktDuration = ath_pkt_duration(
+ sc, rix, bf,
+ (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0,
+ (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG),
+ bf->bf_shpreamble);
+
+ if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) &&
+ (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) {
+ /*
+ * When sending to an HT node that has enabled static
+ * SM/MIMO power save, send at single stream rates but
+ * use maximum allowed transmit chains per user,
+ * hardware, regulatory, or country limits for
+ * better range.
+ */
+ series[i].ChSel = sc->sc_tx_chainmask;
+ } else {
+ if (bf->bf_ht)
+ series[i].ChSel =
+ ath_chainmask_sel_logic(sc, an);
+ else
+ series[i].ChSel = sc->sc_tx_chainmask;
+ }
+
+ if (rtsctsena)
+ series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+
+ /*
+ * Set RTS for all rates if node is in dynamic powersave
+ * mode and we are using dual stream rates.
+ */
+ if (dynamic_mimops && (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG))
+ series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+ }
+
+ /*
+ * For non-HT devices, calculate RTS/CTS duration in software
+ * and disable multi-rate retry.
+ */
+ if (flags && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)) {
+ /*
+ * Compute the transmit duration based on the frame
+ * size and the size of an ACK frame. We call into the
+ * HAL to do the computation since it depends on the
+ * characteristics of the actual PHY being used.
+ *
+ * NB: CTS is assumed the same size as an ACK so we can
+ * use the precalculated ACK durations.
+ */
+ if (flags & ATH9K_TXDESC_RTSENA) { /* SIFS + CTS */
+ ctsduration += bf->bf_shpreamble ?
+ rt->info[cix].spAckDuration :
+ rt->info[cix].lpAckDuration;
+ }
+
+ ctsduration += series[0].PktDuration;
+
+ if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */
+ ctsduration += bf->bf_shpreamble ?
+ rt->info[rix].spAckDuration :
+ rt->info[rix].lpAckDuration;
+ }
+
+ /*
+ * Disable multi-rate retry when using RTS/CTS by clearing
+ * series 1, 2 and 3.
+ */
+ memzero(&series[1], sizeof(struct ath9k_11n_rate_series) * 3);
+ }
+
+ /*
+ * set dur_update_en for l-sig computation except for PS-Poll frames
+ */
+ ath9k_hw_set11n_ratescenario(ah, ds, lastds,
+ !bf->bf_ispspoll,
+ ctsrate,
+ ctsduration,
+ series, 4, flags);
+ if (sc->sc_config.ath_aggr_prot && flags)
+ ath9k_hw_set11n_burstduration(ah, ds, 8192);
+}
+
+/*
+ * Function to send a normal HT (non-AMPDU) frame
+ * NB: must be called with txq lock held
+ */
+
+static int ath_tx_send_normal(struct ath_softc *sc,
+ struct ath_txq *txq,
+ struct ath_atx_tid *tid,
+ struct list_head *bf_head)
+{
+ struct ath_buf *bf;
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *tx_info;
+ struct ath_tx_info_priv *tx_info_priv;
+
+ BUG_ON(list_empty(bf_head));
+
+ bf = list_first_entry(bf_head, struct ath_buf, list);
+ bf->bf_isampdu = 0; /* regular HT frame */
+
+ skb = (struct sk_buff *)bf->bf_mpdu;
+ tx_info = IEEE80211_SKB_CB(skb);
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+ memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
+
+ /* update starting sequence number for subsequent ADDBA request */
+ INCR(tid->seq_start, IEEE80211_SEQ_MAX);
+
+ /* Queue to h/w without aggregation */
+ bf->bf_nframes = 1;
+ bf->bf_lastbf = bf->bf_lastfrm; /* one single frame */
+ ath_buf_set_rate(sc, bf);
+ ath_tx_txqaddbuf(sc, txq, bf_head);
+
+ return 0;
+}
+
+/* flush tid's software queue and send frames as non-ampdu's */
+
+static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
+{
+ struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum];
+ struct ath_buf *bf;
+ struct list_head bf_head;
+ INIT_LIST_HEAD(&bf_head);
+
+ ASSERT(tid->paused > 0);
+ spin_lock_bh(&txq->axq_lock);
+
+ tid->paused--;
+
+ if (tid->paused > 0) {
+ spin_unlock_bh(&txq->axq_lock);
+ return;
+ }
+
+ while (!list_empty(&tid->buf_q)) {
+ bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
+ ASSERT(!bf->bf_isretried);
+ list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list);
+ ath_tx_send_normal(sc, txq, tid, &bf_head);
+ }
+
+ spin_unlock_bh(&txq->axq_lock);
+}
+
+/* Completion routine of an aggregate */
+
+static void ath_tx_complete_aggr_rifs(struct ath_softc *sc,
+ struct ath_txq *txq,
+ struct ath_buf *bf,
+ struct list_head *bf_q,
+ int txok)
+{
+ struct ath_node *an = bf->bf_node;
+ struct ath_atx_tid *tid = ATH_AN_2_TID(an, bf->bf_tidno);
+ struct ath_buf *bf_last = bf->bf_lastbf;
+ struct ath_desc *ds = bf_last->bf_desc;
+ struct ath_buf *bf_next, *bf_lastq = NULL;
+ struct list_head bf_head, bf_pending;
+ u16 seq_st = 0;
+ u32 ba[WME_BA_BMP_SIZE >> 5];
+ int isaggr, txfail, txpending, sendbar = 0, needreset = 0;
+ int isnodegone = (an->an_flags & ATH_NODE_CLEAN);
+
+ isaggr = bf->bf_isaggr;
+ if (isaggr) {
+ if (txok) {
+ if (ATH_DS_TX_BA(ds)) {
+ /*
+ * extract starting sequence and
+ * block-ack bitmap
+ */
+ seq_st = ATH_DS_BA_SEQ(ds);
+ memcpy(ba,
+ ATH_DS_BA_BITMAP(ds),
+ WME_BA_BMP_SIZE >> 3);
+ } else {
+ memzero(ba, WME_BA_BMP_SIZE >> 3);
+
+ /*
+ * AR5416 can become deaf/mute when BA
+ * issue happens. Chip needs to be reset.
+ * But AP code may have sychronization issues
+ * when perform internal reset in this routine.
+ * Only enable reset in STA mode for now.
+ */
+ if (sc->sc_opmode == ATH9K_M_STA)
+ needreset = 1;
+ }
+ } else {
+ memzero(ba, WME_BA_BMP_SIZE >> 3);
+ }
+ }
+
+ INIT_LIST_HEAD(&bf_pending);
+ INIT_LIST_HEAD(&bf_head);
+
+ while (bf) {
+ txfail = txpending = 0;
+ bf_next = bf->bf_next;
+
+ if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf->bf_seqno))) {
+ /* transmit completion, subframe is
+ * acked by block ack */
+ } else if (!isaggr && txok) {
+ /* transmit completion */
+ } else {
+
+ if (!tid->cleanup_inprogress && !isnodegone &&
+ ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
+ if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
+ ath_tx_set_retry(sc, bf);
+ txpending = 1;
+ } else {
+ bf->bf_isxretried = 1;
+ txfail = 1;
+ sendbar = 1;
+ }
+ } else {
+ /*
+ * cleanup in progress, just fail
+ * the un-acked sub-frames
+ */
+ txfail = 1;
+ }
+ }
+ /*
+ * Remove ath_buf's of this sub-frame from aggregate queue.
+ */
+ if (bf_next == NULL) { /* last subframe in the aggregate */
+ ASSERT(bf->bf_lastfrm == bf_last);
+
+ /*
+ * The last descriptor of the last sub frame could be
+ * a holding descriptor for h/w. If that's the case,
+ * bf->bf_lastfrm won't be in the bf_q.
+ * Make sure we handle bf_q properly here.
+ */
+
+ if (!list_empty(bf_q)) {
+ bf_lastq = list_entry(bf_q->prev,
+ struct ath_buf, list);
+ list_cut_position(&bf_head,
+ bf_q, &bf_lastq->list);
+ } else {
+ /*
+ * XXX: if the last subframe only has one
+ * descriptor which is also being used as
+ * a holding descriptor. Then the ath_buf
+ * is not in the bf_q at all.
+ */
+ INIT_LIST_HEAD(&bf_head);
+ }
+ } else {
+ ASSERT(!list_empty(bf_q));
+ list_cut_position(&bf_head,
+ bf_q, &bf->bf_lastfrm->list);
+ }
+
+ if (!txpending) {
+ /*
+ * complete the acked-ones/xretried ones; update
+ * block-ack window
+ */
+ spin_lock_bh(&txq->axq_lock);
+ ath_tx_update_baw(sc, tid, bf->bf_seqno);
+ spin_unlock_bh(&txq->axq_lock);
+
+ /* complete this sub-frame */
+ ath_tx_complete_buf(sc, bf, &bf_head, !txfail, sendbar);
+ } else {
+ /*
+ * retry the un-acked ones
+ */
+ /*
+ * XXX: if the last descriptor is holding descriptor,
+ * in order to requeue the frame to software queue, we
+ * need to allocate a new descriptor and
+ * copy the content of holding descriptor to it.
+ */
+ if (bf->bf_next == NULL &&
+ bf_last->bf_status & ATH_BUFSTATUS_STALE) {
+ struct ath_buf *tbf;
+
+ /* allocate new descriptor */
+ spin_lock_bh(&sc->sc_txbuflock);
+ ASSERT(!list_empty((&sc->sc_txbuf)));
+ tbf = list_first_entry(&sc->sc_txbuf,
+ struct ath_buf, list);
+ list_del(&tbf->list);
+ spin_unlock_bh(&sc->sc_txbuflock);
+
+ ATH_TXBUF_RESET(tbf);
+
+ /* copy descriptor content */
+ tbf->bf_mpdu = bf_last->bf_mpdu;
+ tbf->bf_node = bf_last->bf_node;
+ tbf->bf_buf_addr = bf_last->bf_buf_addr;
+ *(tbf->bf_desc) = *(bf_last->bf_desc);
+
+ /* link it to the frame */
+ if (bf_lastq) {
+ bf_lastq->bf_desc->ds_link =
+ tbf->bf_daddr;
+ bf->bf_lastfrm = tbf;
+ ath9k_hw_cleartxdesc(sc->sc_ah,
+ bf->bf_lastfrm->bf_desc);
+ } else {
+ tbf->bf_state = bf_last->bf_state;
+ tbf->bf_lastfrm = tbf;
+ ath9k_hw_cleartxdesc(sc->sc_ah,
+ tbf->bf_lastfrm->bf_desc);
+
+ /* copy the DMA context */
+ copy_dma_mem_context(
+ get_dma_mem_context(tbf,
+ bf_dmacontext),
+ get_dma_mem_context(bf_last,
+ bf_dmacontext));
+ }
+ list_add_tail(&tbf->list, &bf_head);
+ } else {
+ /*
+ * Clear descriptor status words for
+ * software retry
+ */
+ ath9k_hw_cleartxdesc(sc->sc_ah,
+ bf->bf_lastfrm->bf_desc);
+ }
+
+ /*
+ * Put this buffer to the temporary pending
+ * queue to retain ordering
+ */
+ list_splice_tail_init(&bf_head, &bf_pending);
+ }
+
+ bf = bf_next;
+ }
+
+ /*
+ * node is already gone. no more assocication
+ * with the node. the node might have been freed
+ * any node acces can result in panic.note tid
+ * is part of the node.
+ */
+ if (isnodegone)
+ return;
+
+ if (tid->cleanup_inprogress) {
+ /* check to see if we're done with cleaning the h/w queue */
+ spin_lock_bh(&txq->axq_lock);
+
+ if (tid->baw_head == tid->baw_tail) {
+ tid->addba_exchangecomplete = 0;
+ tid->addba_exchangeattempts = 0;
+ spin_unlock_bh(&txq->axq_lock);
+
+ tid->cleanup_inprogress = false;
+
+ /* send buffered frames as singles */
+ ath_tx_flush_tid(sc, tid);
+ } else
+ spin_unlock_bh(&txq->axq_lock);
+
+ return;
+ }
+
+ /*
+ * prepend un-acked frames to the beginning of the pending frame queue
+ */
+ if (!list_empty(&bf_pending)) {
+ spin_lock_bh(&txq->axq_lock);
+ /* Note: we _prepend_, we _do_not_ at to
+ * the end of the queue ! */
+ list_splice(&bf_pending, &tid->buf_q);
+ ath_tx_queue_tid(txq, tid);
+ spin_unlock_bh(&txq->axq_lock);
+ }
+
+ if (needreset)
+ ath_internal_reset(sc);
+
+ return;
+}
+
+/* Process completed xmit descriptors from the specified queue */
+
+static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_buf *bf, *lastbf, *bf_held = NULL;
+ struct list_head bf_head;
+ struct ath_desc *ds, *tmp_ds;
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *tx_info;
+ struct ath_tx_info_priv *tx_info_priv;
+ int nacked, txok, nbad = 0, isrifs = 0;
+ int status;
+
+ DPRINTF(sc, ATH_DBG_QUEUE,
+ "%s: tx queue %d (%x), link %p\n", __func__,
+ txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
+ txq->axq_link);
+
+ nacked = 0;
+ for (;;) {
+ spin_lock_bh(&txq->axq_lock);
+ txq->axq_intrcnt = 0; /* reset periodic desc intr count */
+ if (list_empty(&txq->axq_q)) {
+ txq->axq_link = NULL;
+ txq->axq_linkbuf = NULL;
+ spin_unlock_bh(&txq->axq_lock);
+ break;
+ }
+ bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
+
+ /*
+ * There is a race condition that a BH gets scheduled
+ * after sw writes TxE and before hw re-load the last
+ * descriptor to get the newly chained one.
+ * Software must keep the last DONE descriptor as a
+ * holding descriptor - software does so by marking
+ * it with the STALE flag.
+ */
+ bf_held = NULL;
+ if (bf->bf_status & ATH_BUFSTATUS_STALE) {
+ bf_held = bf;
+ if (list_is_last(&bf_held->list, &txq->axq_q)) {
+ /* FIXME:
+ * The holding descriptor is the last
+ * descriptor in queue. It's safe to remove
+ * the last holding descriptor in BH context.
+ */
+ spin_unlock_bh(&txq->axq_lock);
+ break;
+ } else {
+ /* Lets work with the next buffer now */
+ bf = list_entry(bf_held->list.next,
+ struct ath_buf, list);
+ }
+ }
+
+ lastbf = bf->bf_lastbf;
+ ds = lastbf->bf_desc; /* NB: last decriptor */
+
+ status = ath9k_hw_txprocdesc(ah, ds);
+ if (status == -EINPROGRESS) {
+ spin_unlock_bh(&txq->axq_lock);
+ break;
+ }
+ if (bf->bf_desc == txq->axq_lastdsWithCTS)
+ txq->axq_lastdsWithCTS = NULL;
+ if (ds == txq->axq_gatingds)
+ txq->axq_gatingds = NULL;
+
+ /*
+ * Remove ath_buf's of the same transmit unit from txq,
+ * however leave the last descriptor back as the holding
+ * descriptor for hw.
+ */
+ lastbf->bf_status |= ATH_BUFSTATUS_STALE;
+ INIT_LIST_HEAD(&bf_head);
+
+ if (!list_is_singular(&lastbf->list))
+ list_cut_position(&bf_head,
+ &txq->axq_q, lastbf->list.prev);
+
+ txq->axq_depth--;
+
+ if (bf->bf_isaggr)
+ txq->axq_aggr_depth--;
+
+ txok = (ds->ds_txstat.ts_status == 0);
+
+ spin_unlock_bh(&txq->axq_lock);
+
+ if (bf_held) {
+ list_del(&bf_held->list);
+ spin_lock_bh(&sc->sc_txbuflock);
+ list_add_tail(&bf_held->list, &sc->sc_txbuf);
+ spin_unlock_bh(&sc->sc_txbuflock);
+ }
+
+ if (!bf->bf_isampdu) {
+ /*
+ * This frame is sent out as a single frame.
+ * Use hardware retry status for this frame.
+ */
+ bf->bf_retries = ds->ds_txstat.ts_longretry;
+ if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY)
+ bf->bf_isxretried = 1;
+ nbad = 0;
+ } else {
+ nbad = ath_tx_num_badfrms(sc, bf, txok);
+ }
+ skb = bf->bf_mpdu;
+ tx_info = IEEE80211_SKB_CB(skb);
+ tx_info_priv = (struct ath_tx_info_priv *)
+ tx_info->driver_data[0];
+ if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
+ tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+ if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
+ (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
+ if (ds->ds_txstat.ts_status == 0)
+ nacked++;
+
+ if (bf->bf_isdata) {
+ if (isrifs)
+ tmp_ds = bf->bf_rifslast->bf_desc;
+ else
+ tmp_ds = ds;
+ memcpy(&tx_info_priv->tx,
+ &tmp_ds->ds_txstat,
+ sizeof(tx_info_priv->tx));
+ tx_info_priv->n_frames = bf->bf_nframes;
+ tx_info_priv->n_bad_frames = nbad;
+ }
+ }
+
+ /*
+ * Complete this transmit unit
+ */
+ if (bf->bf_isampdu)
+ ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, txok);
+ else
+ ath_tx_complete_buf(sc, bf, &bf_head, txok, 0);
+
+ /* Wake up mac80211 queue */
+
+ spin_lock_bh(&txq->axq_lock);
+ if (txq->stopped && ath_txq_depth(sc, txq->axq_qnum) <=
+ (ATH_TXBUF - 20)) {
+ int qnum;
+ qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
+ if (qnum != -1) {
+ ieee80211_wake_queue(sc->hw, qnum);
+ txq->stopped = 0;
+ }
+
+ }
+
+ /*
+ * schedule any pending packets if aggregation is enabled
+ */
+ if (sc->sc_txaggr)
+ ath_txq_schedule(sc, txq);
+ spin_unlock_bh(&txq->axq_lock);
+ }
+ return nacked;
+}
+
+static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_hal *ah = sc->sc_ah;
+
+ (void) ath9k_hw_stoptxdma(ah, txq->axq_qnum);
+ DPRINTF(sc, ATH_DBG_XMIT, "%s: tx queue [%u] %x, link %p\n",
+ __func__, txq->axq_qnum,
+ ath9k_hw_gettxbuf(ah, txq->axq_qnum), txq->axq_link);
+}
+
+/* Drain only the data queues */
+
+static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int i;
+ int npend = 0;
+ enum ath9k_ht_macmode ht_macmode = ath_cwm_macmode(sc);
+
+ /* XXX return value */
+ if (!sc->sc_invalid) {
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i)) {
+ ath_tx_stopdma(sc, &sc->sc_txq[i]);
+
+ /* The TxDMA may not really be stopped.
+ * Double check the hal tx pending count */
+ npend += ath9k_hw_numtxpending(ah,
+ sc->sc_txq[i].axq_qnum);
+ }
+ }
+ }
+
+ if (npend) {
+ int status;
+
+ /* TxDMA not stopped, reset the hal */
+ DPRINTF(sc, ATH_DBG_XMIT,
+ "%s: Unable to stop TxDMA. Reset HAL!\n", __func__);
+
+ spin_lock_bh(&sc->sc_resetlock);
+ if (!ath9k_hw_reset(ah, sc->sc_opmode,
+ &sc->sc_curchan, ht_macmode,
+ sc->sc_tx_chainmask, sc->sc_rx_chainmask,
+ sc->sc_ht_extprotspacing, true, &status)) {
+
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to reset hardware; hal status %u\n",
+ __func__,
+ status);
+ }
+ spin_unlock_bh(&sc->sc_resetlock);
+ }
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i))
+ ath_tx_draintxq(sc, &sc->sc_txq[i], retry_tx);
+ }
+}
+
+/* Add a sub-frame to block ack window */
+
+static void ath_tx_addto_baw(struct ath_softc *sc,
+ struct ath_atx_tid *tid,
+ struct ath_buf *bf)
+{
+ int index, cindex;
+
+ if (bf->bf_isretried)
+ return;
+
+ index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
+ cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
+
+ ASSERT(tid->tx_buf[cindex] == NULL);
+ tid->tx_buf[cindex] = bf;
+
+ if (index >= ((tid->baw_tail - tid->baw_head) &
+ (ATH_TID_MAX_BUFS - 1))) {
+ tid->baw_tail = cindex;
+ INCR(tid->baw_tail, ATH_TID_MAX_BUFS);
+ }
+}
+
+/*
+ * Function to send an A-MPDU
+ * NB: must be called with txq lock held
+ */
+
+static int ath_tx_send_ampdu(struct ath_softc *sc,
+ struct ath_txq *txq,
+ struct ath_atx_tid *tid,
+ struct list_head *bf_head,
+ struct ath_tx_control *txctl)
+{
+ struct ath_buf *bf;
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *tx_info;
+ struct ath_tx_info_priv *tx_info_priv;
+
+ BUG_ON(list_empty(bf_head));
+
+ bf = list_first_entry(bf_head, struct ath_buf, list);
+ bf->bf_isampdu = 1;
+ bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */
+ bf->bf_tidno = txctl->tidno;
+
+ /*
+ * Do not queue to h/w when any of the following conditions is true:
+ * - there are pending frames in software queue
+ * - the TID is currently paused for ADDBA/BAR request
+ * - seqno is not within block-ack window
+ * - h/w queue depth exceeds low water mark
+ */
+ if (!list_empty(&tid->buf_q) || tid->paused ||
+ !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) ||
+ txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
+ /*
+ * Add this frame to software queue for scheduling later
+ * for aggregation.
+ */
+ list_splice_tail_init(bf_head, &tid->buf_q);
+ ath_tx_queue_tid(txq, tid);
+ return 0;
+ }
+
+ skb = (struct sk_buff *)bf->bf_mpdu;
+ tx_info = IEEE80211_SKB_CB(skb);
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+ memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
+
+ /* Add sub-frame to BAW */
+ ath_tx_addto_baw(sc, tid, bf);
+
+ /* Queue to h/w without aggregation */
+ bf->bf_nframes = 1;
+ bf->bf_lastbf = bf->bf_lastfrm; /* one single frame */
+ ath_buf_set_rate(sc, bf);
+ ath_tx_txqaddbuf(sc, txq, bf_head);
+ return 0;
+}
+
+/*
+ * looks up the rate
+ * returns aggr limit based on lowest of the rates
+ */
+
+static u32 ath_lookup_rate(struct ath_softc *sc,
+ struct ath_buf *bf)
+{
+ const struct ath9k_rate_table *rt = sc->sc_currates;
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *tx_info;
+ struct ath_tx_info_priv *tx_info_priv;
+ u32 max_4ms_framelen, frame_length;
+ u16 aggr_limit, legacy = 0, maxampdu;
+ int i;
+
+
+ skb = (struct sk_buff *)bf->bf_mpdu;
+ tx_info = IEEE80211_SKB_CB(skb);
+ tx_info_priv = (struct ath_tx_info_priv *)
+ tx_info->driver_data[0];
+ memcpy(bf->bf_rcs,
+ tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
+
+ /*
+ * Find the lowest frame length among the rate series that will have a
+ * 4ms transmit duration.
+ * TODO - TXOP limit needs to be considered.
+ */
+ max_4ms_framelen = ATH_AMPDU_LIMIT_MAX;
+
+ for (i = 0; i < 4; i++) {
+ if (bf->bf_rcs[i].tries) {
+ frame_length = bf->bf_rcs[i].max_4ms_framelen;
+
+ if (rt->info[bf->bf_rcs[i].rix].phy != PHY_HT) {
+ legacy = 1;
+ break;
+ }
+
+ max_4ms_framelen = min(max_4ms_framelen, frame_length);
+ }
+ }
+
+ /*
+ * limit aggregate size by the minimum rate if rate selected is
+ * not a probe rate, if rate selected is a probe rate then
+ * avoid aggregation of this packet.
+ */
+ if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
+ return 0;
+
+ aggr_limit = min(max_4ms_framelen,
+ (u32)ATH_AMPDU_LIMIT_DEFAULT);
+
+ /*
+ * h/w can accept aggregates upto 16 bit lengths (65535).
+ * The IE, however can hold upto 65536, which shows up here
+ * as zero. Ignore 65536 since we are constrained by hw.
+ */
+ maxampdu = sc->sc_ht_info.maxampdu;
+ if (maxampdu)
+ aggr_limit = min(aggr_limit, maxampdu);
+
+ return aggr_limit;
+}
+
+/*
+ * returns the number of delimiters to be added to
+ * meet the minimum required mpdudensity.
+ * caller should make sure that the rate is HT rate .
+ */
+
+static int ath_compute_num_delims(struct ath_softc *sc,
+ struct ath_buf *bf,
+ u16 frmlen)
+{
+ const struct ath9k_rate_table *rt = sc->sc_currates;
+ u32 nsymbits, nsymbols, mpdudensity;
+ u16 minlen;
+ u8 rc, flags, rix;
+ int width, half_gi, ndelim, mindelim;
+
+ /* Select standard number of delimiters based on frame length alone */
+ ndelim = ATH_AGGR_GET_NDELIM(frmlen);
+
+ /*
+ * If encryption enabled, hardware requires some more padding between
+ * subframes.
+ * TODO - this could be improved to be dependent on the rate.
+ * The hardware can keep up at lower rates, but not higher rates
+ */
+ if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR)
+ ndelim += ATH_AGGR_ENCRYPTDELIM;
+
+ /*
+ * Convert desired mpdu density from microeconds to bytes based
+ * on highest rate in rate series (i.e. first rate) to determine
+ * required minimum length for subframe. Take into account
+ * whether high rate is 20 or 40Mhz and half or full GI.
+ */
+ mpdudensity = sc->sc_ht_info.mpdudensity;
+
+ /*
+ * If there is no mpdu density restriction, no further calculation
+ * is needed.
+ */
+ if (mpdudensity == 0)
+ return ndelim;
+
+ rix = bf->bf_rcs[0].rix;
+ flags = bf->bf_rcs[0].flags;
+ rc = rt->info[rix].rateCode;
+ width = (flags & ATH_RC_CW40_FLAG) ? 1 : 0;
+ half_gi = (flags & ATH_RC_SGI_FLAG) ? 1 : 0;
+
+ if (half_gi)
+ nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity);
+ else
+ nsymbols = NUM_SYMBOLS_PER_USEC(mpdudensity);
+
+ if (nsymbols == 0)
+ nsymbols = 1;
+
+ nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
+ minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
+
+ /* Is frame shorter than required minimum length? */
+ if (frmlen < minlen) {
+ /* Get the minimum number of delimiters required. */
+ mindelim = (minlen - frmlen) / ATH_AGGR_DELIM_SZ;
+ ndelim = max(mindelim, ndelim);
+ }
+
+ return ndelim;
+}
+
+/*
+ * For aggregation from software buffer queue.
+ * NB: must be called with txq lock held
+ */
+
+static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
+ struct ath_atx_tid *tid,
+ struct list_head *bf_q,
+ struct ath_buf **bf_last,
+ struct aggr_rifs_param *param,
+ int *prev_frames)
+{
+#define PADBYTES(_len) ((4 - ((_len) % 4)) % 4)
+ struct ath_buf *bf, *tbf, *bf_first, *bf_prev = NULL;
+ struct list_head bf_head;
+ int rl = 0, nframes = 0, ndelim;
+ u16 aggr_limit = 0, al = 0, bpad = 0,
+ al_delta, h_baw = tid->baw_size / 2;
+ enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
+ int prev_al = 0, is_ds_rate = 0;
+ INIT_LIST_HEAD(&bf_head);
+
+ BUG_ON(list_empty(&tid->buf_q));
+
+ bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
+
+ do {
+ bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
+
+ /*
+ * do not step over block-ack window
+ */
+ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno)) {
+ status = ATH_AGGR_BAW_CLOSED;
+ break;
+ }
+
+ if (!rl) {
+ aggr_limit = ath_lookup_rate(sc, bf);
+ rl = 1;
+ /*
+ * Is rate dual stream
+ */
+ is_ds_rate =
+ (bf->bf_rcs[0].flags & ATH_RC_DS_FLAG) ? 1 : 0;
+ }
+
+ /*
+ * do not exceed aggregation limit
+ */
+ al_delta = ATH_AGGR_DELIM_SZ + bf->bf_frmlen;
+
+ if (nframes && (aggr_limit <
+ (al + bpad + al_delta + prev_al))) {
+ status = ATH_AGGR_LIMITED;
+ break;
+ }
+
+ /*
+ * do not exceed subframe limit
+ */
+ if ((nframes + *prev_frames) >=
+ min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
+ status = ATH_AGGR_LIMITED;
+ break;
+ }
+
+ /*
+ * add padding for previous frame to aggregation length
+ */
+ al += bpad + al_delta;
+
+ /*
+ * Get the delimiters needed to meet the MPDU
+ * density for this node.
+ */
+ ndelim = ath_compute_num_delims(sc, bf_first, bf->bf_frmlen);
+
+ bpad = PADBYTES(al_delta) + (ndelim << 2);
+
+ bf->bf_next = NULL;
+ bf->bf_lastfrm->bf_desc->ds_link = 0;
+
+ /*
+ * this packet is part of an aggregate
+ * - remove all descriptors belonging to this frame from
+ * software queue
+ * - add it to block ack window
+ * - set up descriptors for aggregation
+ */
+ list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list);
+ ath_tx_addto_baw(sc, tid, bf);
+
+ list_for_each_entry(tbf, &bf_head, list) {
+ ath9k_hw_set11n_aggr_middle(sc->sc_ah,
+ tbf->bf_desc, ndelim);
+ }
+
+ /*
+ * link buffers of this frame to the aggregate
+ */
+ list_splice_tail_init(&bf_head, bf_q);
+ nframes++;
+
+ if (bf_prev) {
+ bf_prev->bf_next = bf;
+ bf_prev->bf_lastfrm->bf_desc->ds_link = bf->bf_daddr;
+ }
+ bf_prev = bf;
+
+#ifdef AGGR_NOSHORT
+ /*
+ * terminate aggregation on a small packet boundary
+ */
+ if (bf->bf_frmlen < ATH_AGGR_MINPLEN) {
+ status = ATH_AGGR_SHORTPKT;
+ break;
+ }
+#endif
+ } while (!list_empty(&tid->buf_q));
+
+ bf_first->bf_al = al;
+ bf_first->bf_nframes = nframes;
+ *bf_last = bf_prev;
+ return status;
+#undef PADBYTES
+}
+
+/*
+ * process pending frames possibly doing a-mpdu aggregation
+ * NB: must be called with txq lock held
+ */
+
+static void ath_tx_sched_aggr(struct ath_softc *sc,
+ struct ath_txq *txq, struct ath_atx_tid *tid)
+{
+ struct ath_buf *bf, *tbf, *bf_last, *bf_lastaggr = NULL;
+ enum ATH_AGGR_STATUS status;
+ struct list_head bf_q;
+ struct aggr_rifs_param param = {0, 0, 0, 0, NULL};
+ int prev_frames = 0;
+
+ do {
+ if (list_empty(&tid->buf_q))
+ return;
+
+ INIT_LIST_HEAD(&bf_q);
+
+ status = ath_tx_form_aggr(sc, tid, &bf_q, &bf_lastaggr, &param,
+ &prev_frames);
+
+ /*
+ * no frames picked up to be aggregated; block-ack
+ * window is not open
+ */
+ if (list_empty(&bf_q))
+ break;
+
+ bf = list_first_entry(&bf_q, struct ath_buf, list);
+ bf_last = list_entry(bf_q.prev, struct ath_buf, list);
+ bf->bf_lastbf = bf_last;
+
+ /*
+ * if only one frame, send as non-aggregate
+ */
+ if (bf->bf_nframes == 1) {
+ ASSERT(bf->bf_lastfrm == bf_last);
+
+ bf->bf_isaggr = 0;
+ /*
+ * clear aggr bits for every descriptor
+ * XXX TODO: is there a way to optimize it?
+ */
+ list_for_each_entry(tbf, &bf_q, list) {
+ ath9k_hw_clr11n_aggr(sc->sc_ah, tbf->bf_desc);
+ }
+
+ ath_buf_set_rate(sc, bf);
+ ath_tx_txqaddbuf(sc, txq, &bf_q);
+ continue;
+ }
+
+ /*
+ * setup first desc with rate and aggr info
+ */
+ bf->bf_isaggr = 1;
+ ath_buf_set_rate(sc, bf);
+ ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, bf->bf_al);
+
+ /*
+ * anchor last frame of aggregate correctly
+ */
+ ASSERT(bf_lastaggr);
+ ASSERT(bf_lastaggr->bf_lastfrm == bf_last);
+ tbf = bf_lastaggr;
+ ath9k_hw_set11n_aggr_last(sc->sc_ah, tbf->bf_desc);
+
+ /* XXX: We don't enter into this loop, consider removing this */
+ while (!list_empty(&bf_q) && !list_is_last(&tbf->list, &bf_q)) {
+ tbf = list_entry(tbf->list.next, struct ath_buf, list);
+ ath9k_hw_set11n_aggr_last(sc->sc_ah, tbf->bf_desc);
+ }
+
+ txq->axq_aggr_depth++;
+
+ /*
+ * Normal aggregate, queue to hardware
+ */
+ ath_tx_txqaddbuf(sc, txq, &bf_q);
+
+ } while (txq->axq_depth < ATH_AGGR_MIN_QDEPTH &&
+ status != ATH_AGGR_BAW_CLOSED);
+}
+
+/* Called with txq lock held */
+
+static void ath_tid_drain(struct ath_softc *sc,
+ struct ath_txq *txq,
+ struct ath_atx_tid *tid,
+ bool bh_flag)
+{
+ struct ath_buf *bf;
+ struct list_head bf_head;
+ INIT_LIST_HEAD(&bf_head);
+
+ for (;;) {
+ if (list_empty(&tid->buf_q))
+ break;
+ bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
+
+ list_cut_position(&bf_head, &tid->buf_q, &bf->bf_lastfrm->list);
+
+ /* update baw for software retried frame */
+ if (bf->bf_isretried)
+ ath_tx_update_baw(sc, tid, bf->bf_seqno);
+
+ /*
+ * do not indicate packets while holding txq spinlock.
+ * unlock is intentional here
+ */
+ if (likely(bh_flag))
+ spin_unlock_bh(&txq->axq_lock);
+ else
+ spin_unlock(&txq->axq_lock);
+
+ /* complete this sub-frame */
+ ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
+
+ if (likely(bh_flag))
+ spin_lock_bh(&txq->axq_lock);
+ else
+ spin_lock(&txq->axq_lock);
+ }
+
+ /*
+ * TODO: For frame(s) that are in the retry state, we will reuse the
+ * sequence number(s) without setting the retry bit. The
+ * alternative is to give up on these and BAR the receiver's window
+ * forward.
+ */
+ tid->seq_next = tid->seq_start;
+ tid->baw_tail = tid->baw_head;
+}
+
+/*
+ * Drain all pending buffers
+ * NB: must be called with txq lock held
+ */
+
+static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
+ struct ath_txq *txq,
+ bool bh_flag)
+{
+ struct ath_atx_ac *ac, *ac_tmp;
+ struct ath_atx_tid *tid, *tid_tmp;
+
+ list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
+ list_del(&ac->list);
+ ac->sched = false;
+ list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) {
+ list_del(&tid->list);
+ tid->sched = false;
+ ath_tid_drain(sc, txq, tid, bh_flag);
+ }
+ }
+}
+
+static int ath_tx_start_dma(struct ath_softc *sc,
+ struct sk_buff *skb,
+ struct scatterlist *sg,
+ u32 n_sg,
+ struct ath_tx_control *txctl)
+{
+ struct ath_node *an = txctl->an;
+ struct ath_buf *bf = NULL;
+ struct list_head bf_head;
+ struct ath_desc *ds;
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath_txq *txq = &sc->sc_txq[txctl->qnum];
+ struct ath_tx_info_priv *tx_info_priv;
+ struct ath_rc_series *rcs;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ __le16 fc = hdr->frame_control;
+
+ /* For each sglist entry, allocate an ath_buf for DMA */
+ INIT_LIST_HEAD(&bf_head);
+ spin_lock_bh(&sc->sc_txbuflock);
+ if (unlikely(list_empty(&sc->sc_txbuf))) {
+ spin_unlock_bh(&sc->sc_txbuflock);
+ return -ENOMEM;
+ }
+
+ bf = list_first_entry(&sc->sc_txbuf, struct ath_buf, list);
+ list_del(&bf->list);
+ spin_unlock_bh(&sc->sc_txbuflock);
+
+ list_add_tail(&bf->list, &bf_head);
+
+ /* set up this buffer */
+ ATH_TXBUF_RESET(bf);
+ bf->bf_frmlen = txctl->frmlen;
+ bf->bf_isdata = ieee80211_is_data(fc);
+ bf->bf_isbar = ieee80211_is_back_req(fc);
+ bf->bf_ispspoll = ieee80211_is_pspoll(fc);
+ bf->bf_flags = txctl->flags;
+ bf->bf_shpreamble = sc->sc_flags & ATH_PREAMBLE_SHORT;
+ bf->bf_keytype = txctl->keytype;
+ tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+ rcs = tx_info_priv->rcs;
+ bf->bf_rcs[0] = rcs[0];
+ bf->bf_rcs[1] = rcs[1];
+ bf->bf_rcs[2] = rcs[2];
+ bf->bf_rcs[3] = rcs[3];
+ bf->bf_node = an;
+ bf->bf_mpdu = skb;
+ bf->bf_buf_addr = sg_dma_address(sg);
+
+ /* setup descriptor */
+ ds = bf->bf_desc;
+ ds->ds_link = 0;
+ ds->ds_data = bf->bf_buf_addr;
+
+ /*
+ * Save the DMA context in the first ath_buf
+ */
+ copy_dma_mem_context(get_dma_mem_context(bf, bf_dmacontext),
+ get_dma_mem_context(txctl, dmacontext));
+
+ /*
+ * Formulate first tx descriptor with tx controls.
+ */
+ ath9k_hw_set11n_txdesc(ah,
+ ds,
+ bf->bf_frmlen, /* frame length */
+ txctl->atype, /* Atheros packet type */
+ min(txctl->txpower, (u16)60), /* txpower */
+ txctl->keyix, /* key cache index */
+ txctl->keytype, /* key type */
+ txctl->flags); /* flags */
+ ath9k_hw_filltxdesc(ah,
+ ds,
+ sg_dma_len(sg), /* segment length */
+ true, /* first segment */
+ (n_sg == 1) ? true : false, /* last segment */
+ ds); /* first descriptor */
+
+ bf->bf_lastfrm = bf;
+ bf->bf_ht = txctl->ht;
+
+ spin_lock_bh(&txq->axq_lock);
+
+ if (txctl->ht && sc->sc_txaggr) {
+ struct ath_atx_tid *tid = ATH_AN_2_TID(an, txctl->tidno);
+ if (ath_aggr_query(sc, an, txctl->tidno)) {
+ /*
+ * Try aggregation if it's a unicast data frame
+ * and the destination is HT capable.
+ */
+ ath_tx_send_ampdu(sc, txq, tid, &bf_head, txctl);
+ } else {
+ /*
+ * Send this frame as regular when ADDBA exchange
+ * is neither complete nor pending.
+ */
+ ath_tx_send_normal(sc, txq, tid, &bf_head);
+ }
+ } else {
+ bf->bf_lastbf = bf;
+ bf->bf_nframes = 1;
+ ath_buf_set_rate(sc, bf);
+
+ if (ieee80211_is_back_req(fc)) {
+ /* This is required for resuming tid
+ * during BAR completion */
+ bf->bf_tidno = txctl->tidno;
+ }
+
+ if (is_multicast_ether_addr(hdr->addr1)) {
+ struct ath_vap *avp = sc->sc_vaps[txctl->if_id];
+
+ /*
+ * When servicing one or more stations in power-save
+ * mode (or) if there is some mcast data waiting on
+ * mcast queue (to prevent out of order delivery of
+ * mcast,bcast packets) multicast frames must be
+ * buffered until after the beacon. We use the private
+ * mcast queue for that.
+ */
+ /* XXX? more bit in 802.11 frame header */
+ spin_lock_bh(&avp->av_mcastq.axq_lock);
+ if (txctl->ps || avp->av_mcastq.axq_depth)
+ ath_tx_mcastqaddbuf(sc,
+ &avp->av_mcastq, &bf_head);
+ else
+ ath_tx_txqaddbuf(sc, txq, &bf_head);
+ spin_unlock_bh(&avp->av_mcastq.axq_lock);
+ } else
+ ath_tx_txqaddbuf(sc, txq, &bf_head);
+ }
+ spin_unlock_bh(&txq->axq_lock);
+ return 0;
+}
+
+static void xmit_map_sg(struct ath_softc *sc,
+ struct sk_buff *skb,
+ dma_addr_t *pa,
+ struct ath_tx_control *txctl)
+{
+ struct ath_xmit_status tx_status;
+ struct ath_atx_tid *tid;
+ struct scatterlist sg;
+
+ *pa = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+ /* setup S/G list */
+ memset(&sg, 0, sizeof(struct scatterlist));
+ sg_dma_address(&sg) = *pa;
+ sg_dma_len(&sg) = skb->len;
+
+ if (ath_tx_start_dma(sc, skb, &sg, 1, txctl) != 0) {
+ /*
+ * We have to do drop frame here.
+ */
+ pci_unmap_single(sc->pdev, *pa, skb->len, PCI_DMA_TODEVICE);
+
+ tx_status.retries = 0;
+ tx_status.flags = ATH_TX_ERROR;
+
+ if (txctl->ht && sc->sc_txaggr) {
+ /* Reclaim the seqno. */
+ tid = ATH_AN_2_TID((struct ath_node *)
+ txctl->an, txctl->tidno);
+ DECR(tid->seq_next, IEEE80211_SEQ_MAX);
+ }
+ ath_tx_complete(sc, skb, &tx_status, txctl->an);
+ }
+}
+
+/* Initialize TX queue and h/w */
+
+int ath_tx_init(struct ath_softc *sc, int nbufs)
+{
+ int error = 0;
+
+ do {
+ spin_lock_init(&sc->sc_txbuflock);
+
+ /* Setup tx descriptors */
+ error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf,
+ "tx", nbufs * ATH_FRAG_PER_MSDU, ATH_TXDESC);
+ if (error != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: failed to allocate tx descriptors: %d\n",
+ __func__, error);
+ break;
+ }
+
+ /* XXX allocate beacon state together with vap */
+ error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
+ "beacon", ATH_BCBUF, 1);
+ if (error != 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: failed to allocate "
+ "beacon descripotrs: %d\n",
+ __func__, error);
+ break;
+ }
+
+ } while (0);
+
+ if (error != 0)
+ ath_tx_cleanup(sc);
+
+ return error;
+}
+
+/* Reclaim all tx queue resources */
+
+int ath_tx_cleanup(struct ath_softc *sc)
+{
+ /* cleanup beacon descriptors */
+ if (sc->sc_bdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf);
+
+ /* cleanup tx descriptors */
+ if (sc->sc_txdma.dd_desc_len != 0)
+ ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
+
+ return 0;
+}
+
+/* Setup a h/w transmit queue */
+
+struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ struct ath9k_tx_queue_info qi;
+ int qnum;
+
+ memzero(&qi, sizeof(qi));
+ qi.tqi_subtype = subtype;
+ qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
+ qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
+ qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
+ qi.tqi_physCompBuf = 0;
+
+ /*
+ * Enable interrupts only for EOL and DESC conditions.
+ * We mark tx descriptors to receive a DESC interrupt
+ * when a tx queue gets deep; otherwise waiting for the
+ * EOL to reap descriptors. Note that this is done to
+ * reduce interrupt load and this only defers reaping
+ * descriptors, never transmitting frames. Aside from
+ * reducing interrupts this also permits more concurrency.
+ * The only potential downside is if the tx queue backs
+ * up in which case the top half of the kernel may backup
+ * due to a lack of tx descriptors.
+ *
+ * The UAPSD queue is an exception, since we take a desc-
+ * based intr on the EOSP frames.
+ */
+ if (qtype == ATH9K_TX_QUEUE_UAPSD)
+ qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
+ else
+ qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
+ TXQ_FLAG_TXDESCINT_ENABLE;
+ qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
+ if (qnum == -1) {
+ /*
+ * NB: don't print a message, this happens
+ * normally on parts with too few tx queues
+ */
+ return NULL;
+ }
+ if (qnum >= ARRAY_SIZE(sc->sc_txq)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: hal qnum %u out of range, max %u!\n",
+ __func__, qnum, (unsigned int)ARRAY_SIZE(sc->sc_txq));
+ ath9k_hw_releasetxqueue(ah, qnum);
+ return NULL;
+ }
+ if (!ATH_TXQ_SETUP(sc, qnum)) {
+ struct ath_txq *txq = &sc->sc_txq[qnum];
+
+ txq->axq_qnum = qnum;
+ txq->axq_link = NULL;
+ INIT_LIST_HEAD(&txq->axq_q);
+ INIT_LIST_HEAD(&txq->axq_acq);
+ spin_lock_init(&txq->axq_lock);
+ txq->axq_depth = 0;
+ txq->axq_aggr_depth = 0;
+ txq->axq_totalqueued = 0;
+ txq->axq_intrcnt = 0;
+ txq->axq_linkbuf = NULL;
+ sc->sc_txqsetup |= 1<<qnum;
+ }
+ return &sc->sc_txq[qnum];
+}
+
+/* Reclaim resources for a setup queue */
+
+void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq)
+{
+ ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum);
+ sc->sc_txqsetup &= ~(1<<txq->axq_qnum);
+}
+
+/*
+ * Setup a hardware data transmit queue for the specified
+ * access control. The hal may not support all requested
+ * queues in which case it will return a reference to a
+ * previously setup queue. We record the mapping from ac's
+ * to h/w queues for use by ath_tx_start and also track
+ * the set of h/w queues being used to optimize work in the
+ * transmit interrupt handler and related routines.
+ */
+
+int ath_tx_setup(struct ath_softc *sc, int haltype)
+{
+ struct ath_txq *txq;
+
+ if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: HAL AC %u out of range, max %zu!\n",
+ __func__, haltype, ARRAY_SIZE(sc->sc_haltype2q));
+ return 0;
+ }
+ txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
+ if (txq != NULL) {
+ sc->sc_haltype2q[haltype] = txq->axq_qnum;
+ return 1;
+ } else
+ return 0;
+}
+
+int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
+{
+ int qnum;
+
+ switch (qtype) {
+ case ATH9K_TX_QUEUE_DATA:
+ if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: HAL AC %u out of range, max %zu!\n",
+ __func__,
+ haltype, ARRAY_SIZE(sc->sc_haltype2q));
+ return -1;
+ }
+ qnum = sc->sc_haltype2q[haltype];
+ break;
+ case ATH9K_TX_QUEUE_BEACON:
+ qnum = sc->sc_bhalq;
+ break;
+ case ATH9K_TX_QUEUE_CAB:
+ qnum = sc->sc_cabq->axq_qnum;
+ break;
+ default:
+ qnum = -1;
+ }
+ return qnum;
+}
+
+/* Update parameters for a transmit queue */
+
+int ath_txq_update(struct ath_softc *sc, int qnum,
+ struct ath9k_tx_queue_info *qinfo)
+{
+ struct ath_hal *ah = sc->sc_ah;
+ int error = 0;
+ struct ath9k_tx_queue_info qi;
+
+ if (qnum == sc->sc_bhalq) {
+ /*
+ * XXX: for beacon queue, we just save the parameter.
+ * It will be picked up by ath_beaconq_config when
+ * it's necessary.
+ */
+ sc->sc_beacon_qi = *qinfo;
+ return 0;
+ }
+
+ ASSERT(sc->sc_txq[qnum].axq_qnum == qnum);
+
+ ath9k_hw_get_txq_props(ah, qnum, &qi);
+ qi.tqi_aifs = qinfo->tqi_aifs;
+ qi.tqi_cwmin = qinfo->tqi_cwmin;
+ qi.tqi_cwmax = qinfo->tqi_cwmax;
+ qi.tqi_burstTime = qinfo->tqi_burstTime;
+ qi.tqi_readyTime = qinfo->tqi_readyTime;
+
+ if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: unable to update hardware queue %u!\n",
+ __func__, qnum);
+ error = -EIO;
+ } else {
+ ath9k_hw_resettxqueue(ah, qnum); /* push to h/w */
+ }
+
+ return error;
+}
+
+int ath_cabq_update(struct ath_softc *sc)
+{
+ struct ath9k_tx_queue_info qi;
+ int qnum = sc->sc_cabq->axq_qnum;
+ struct ath_beacon_config conf;
+
+ ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
+ /*
+ * Ensure the readytime % is within the bounds.
+ */
+ if (sc->sc_config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
+ sc->sc_config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
+ else if (sc->sc_config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
+ sc->sc_config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
+
+ ath_get_beaconconfig(sc, ATH_IF_ID_ANY, &conf);
+ qi.tqi_readyTime =
+ (conf.beacon_interval * sc->sc_config.cabqReadytime) / 100;
+ ath_txq_update(sc, qnum, &qi);
+
+ return 0;
+}
+
+int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb)
+{
+ struct ath_tx_control txctl;
+ int error = 0;
+
+ error = ath_tx_prepare(sc, skb, &txctl);
+ if (error == 0)
+ /*
+ * Start DMA mapping.
+ * ath_tx_start_dma() will be called either synchronously
+ * or asynchrounsly once DMA is complete.
+ */
+ xmit_map_sg(sc, skb,
+ get_dma_mem_context(&txctl, dmacontext),
+ &txctl);
+ else
+ ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE);
+
+ /* failed packets will be dropped by the caller */
+ return error;
+}
+
+/* Deferred processing of transmit interrupt */
+
+void ath_tx_tasklet(struct ath_softc *sc)
+{
+ u64 tsf = ath9k_hw_gettsf64(sc->sc_ah);
+ int i, nacked = 0;
+ u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);
+
+ ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);
+
+ /*
+ * Process each active queue.
+ */
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
+ nacked += ath_tx_processq(sc, &sc->sc_txq[i]);
+ }
+ if (nacked)
+ sc->sc_lastrx = tsf;
+}
+
+void ath_tx_draintxq(struct ath_softc *sc,
+ struct ath_txq *txq, bool retry_tx)
+{
+ struct ath_buf *bf, *lastbf;
+ struct list_head bf_head;
+
+ INIT_LIST_HEAD(&bf_head);
+
+ /*
+ * NB: this assumes output has been stopped and
+ * we do not need to block ath_tx_tasklet
+ */
+ for (;;) {
+ spin_lock_bh(&txq->axq_lock);
+
+ if (list_empty(&txq->axq_q)) {
+ txq->axq_link = NULL;
+ txq->axq_linkbuf = NULL;
+ spin_unlock_bh(&txq->axq_lock);
+ break;
+ }
+
+ bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
+
+ if (bf->bf_status & ATH_BUFSTATUS_STALE) {
+ list_del(&bf->list);
+ spin_unlock_bh(&txq->axq_lock);
+
+ spin_lock_bh(&sc->sc_txbuflock);
+ list_add_tail(&bf->list, &sc->sc_txbuf);
+ spin_unlock_bh(&sc->sc_txbuflock);
+ continue;
+ }
+
+ lastbf = bf->bf_lastbf;
+ if (!retry_tx)
+ lastbf->bf_desc->ds_txstat.ts_flags =
+ ATH9K_TX_SW_ABORTED;
+
+ /* remove ath_buf's of the same mpdu from txq */
+ list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
+ txq->axq_depth--;
+
+ spin_unlock_bh(&txq->axq_lock);
+
+ if (bf->bf_isampdu)
+ ath_tx_complete_aggr_rifs(sc, txq, bf, &bf_head, 0);
+ else
+ ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
+ }
+
+ /* flush any pending frames if aggregation is enabled */
+ if (sc->sc_txaggr) {
+ if (!retry_tx) {
+ spin_lock_bh(&txq->axq_lock);
+ ath_txq_drain_pending_buffers(sc, txq,
+ ATH9K_BH_STATUS_CHANGE);
+ spin_unlock_bh(&txq->axq_lock);
+ }
+ }
+}
+
+/* Drain the transmit queues and reclaim resources */
+
+void ath_draintxq(struct ath_softc *sc, bool retry_tx)
+{
+ /* stop beacon queue. The beacon will be freed when
+ * we go to INIT state */
+ if (!sc->sc_invalid) {
+ (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq);
+ DPRINTF(sc, ATH_DBG_XMIT, "%s: beacon queue %x\n", __func__,
+ ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq));
+ }
+
+ ath_drain_txdataq(sc, retry_tx);
+}
+
+u32 ath_txq_depth(struct ath_softc *sc, int qnum)
+{
+ return sc->sc_txq[qnum].axq_depth;
+}
+
+u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum)
+{
+ return sc->sc_txq[qnum].axq_aggr_depth;
+}
+
+/* Check if an ADDBA is required. A valid node must be passed. */
+enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc,
+ struct ath_node *an,
+ u8 tidno)
+{
+ struct ath_atx_tid *txtid;
+ DECLARE_MAC_BUF(mac);
+
+ if (!sc->sc_txaggr)
+ return AGGR_NOT_REQUIRED;
+
+ /* ADDBA exchange must be completed before sending aggregates */
+ txtid = ATH_AN_2_TID(an, tidno);
+
+ if (txtid->addba_exchangecomplete)
+ return AGGR_EXCHANGE_DONE;
+
+ if (txtid->cleanup_inprogress)
+ return AGGR_CLEANUP_PROGRESS;
+
+ if (txtid->addba_exchangeinprogress)
+ return AGGR_EXCHANGE_PROGRESS;
+
+ if (!txtid->addba_exchangecomplete) {
+ if (!txtid->addba_exchangeinprogress &&
+ (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) {
+ txtid->addba_exchangeattempts++;
+ return AGGR_REQUIRED;
+ }
+ }
+
+ return AGGR_NOT_REQUIRED;
+}
+
+/* Start TX aggregation */
+
+int ath_tx_aggr_start(struct ath_softc *sc,
+ const u8 *addr,
+ u16 tid,
+ u16 *ssn)
+{
+ struct ath_atx_tid *txtid;
+ struct ath_node *an;
+
+ spin_lock_bh(&sc->node_lock);
+ an = ath_node_find(sc, (u8 *) addr);
+ spin_unlock_bh(&sc->node_lock);
+
+ if (!an) {
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: Node not found to initialize "
+ "TX aggregation\n", __func__);
+ return -1;
+ }
+
+ if (sc->sc_txaggr) {
+ txtid = ATH_AN_2_TID(an, tid);
+ txtid->addba_exchangeinprogress = 1;
+ ath_tx_pause_tid(sc, txtid);
+ }
+
+ return 0;
+}
+
+/* Stop tx aggregation */
+
+int ath_tx_aggr_stop(struct ath_softc *sc,
+ const u8 *addr,
+ u16 tid)
+{
+ struct ath_node *an;
+
+ spin_lock_bh(&sc->node_lock);
+ an = ath_node_find(sc, (u8 *) addr);
+ spin_unlock_bh(&sc->node_lock);
+
+ if (!an) {
+ DPRINTF(sc, ATH_DBG_AGGR,
+ "%s: TX aggr stop for non-existent node\n", __func__);
+ return -1;
+ }
+
+ ath_tx_aggr_teardown(sc, an, tid);
+ return 0;
+}
+
+/*
+ * Performs transmit side cleanup when TID changes from aggregated to
+ * unaggregated.
+ * - Pause the TID and mark cleanup in progress
+ * - Discard all retry frames from the s/w queue.
+ */
+
+void ath_tx_aggr_teardown(struct ath_softc *sc,
+ struct ath_node *an, u8 tid)
+{
+ struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
+ struct ath_txq *txq = &sc->sc_txq[txtid->ac->qnum];
+ struct ath_buf *bf;
+ struct list_head bf_head;
+ INIT_LIST_HEAD(&bf_head);
+
+ DPRINTF(sc, ATH_DBG_AGGR, "%s: teardown TX aggregation\n", __func__);
+
+ if (txtid->cleanup_inprogress) /* cleanup is in progress */
+ return;
+
+ if (!txtid->addba_exchangecomplete) {
+ txtid->addba_exchangeattempts = 0;
+ return;
+ }
+
+ /* TID must be paused first */
+ ath_tx_pause_tid(sc, txtid);
+
+ /* drop all software retried frames and mark this TID */
+ spin_lock_bh(&txq->axq_lock);
+ while (!list_empty(&txtid->buf_q)) {
+ bf = list_first_entry(&txtid->buf_q, struct ath_buf, list);
+ if (!bf->bf_isretried) {
+ /*
+ * NB: it's based on the assumption that
+ * software retried frame will always stay
+ * at the head of software queue.
+ */
+ break;
+ }
+ list_cut_position(&bf_head,
+ &txtid->buf_q, &bf->bf_lastfrm->list);
+ ath_tx_update_baw(sc, txtid, bf->bf_seqno);
+
+ /* complete this sub-frame */
+ ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
+ }
+
+ if (txtid->baw_head != txtid->baw_tail) {
+ spin_unlock_bh(&txq->axq_lock);
+ txtid->cleanup_inprogress = true;
+ } else {
+ txtid->addba_exchangecomplete = 0;
+ txtid->addba_exchangeattempts = 0;
+ spin_unlock_bh(&txq->axq_lock);
+ ath_tx_flush_tid(sc, txtid);
+ }
+}
+
+/*
+ * Tx scheduling logic
+ * NB: must be called with txq lock held
+ */
+
+void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
+{
+ struct ath_atx_ac *ac;
+ struct ath_atx_tid *tid;
+
+ /* nothing to schedule */
+ if (list_empty(&txq->axq_acq))
+ return;
+ /*
+ * get the first node/ac pair on the queue
+ */
+ ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
+ list_del(&ac->list);
+ ac->sched = false;
+
+ /*
+ * process a single tid per destination
+ */
+ do {
+ /* nothing to schedule */
+ if (list_empty(&ac->tid_q))
+ return;
+
+ tid = list_first_entry(&ac->tid_q, struct ath_atx_tid, list);
+ list_del(&tid->list);
+ tid->sched = false;
+
+ if (tid->paused) /* check next tid to keep h/w busy */
+ continue;
+
+ if (!(tid->an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) ||
+ ((txq->axq_depth % 2) == 0)) {
+ ath_tx_sched_aggr(sc, txq, tid);
+ }
+
+ /*
+ * add tid to round-robin queue if more frames
+ * are pending for the tid
+ */
+ if (!list_empty(&tid->buf_q))
+ ath_tx_queue_tid(txq, tid);
+
+ /* only schedule one TID at a time */
+ break;
+ } while (!list_empty(&ac->tid_q));
+
+ /*
+ * schedule AC if more TIDs need processing
+ */
+ if (!list_empty(&ac->tid_q)) {
+ /*
+ * add dest ac to txq if not already added
+ */
+ if (!ac->sched) {
+ ac->sched = true;
+ list_add_tail(&ac->list, &txq->axq_acq);
+ }
+ }
+}
+
+/* Initialize per-node transmit state */
+
+void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
+{
+ if (sc->sc_txaggr) {
+ struct ath_atx_tid *tid;
+ struct ath_atx_ac *ac;
+ int tidno, acno;
+
+ sc->sc_ht_info.maxampdu = ATH_AMPDU_LIMIT_DEFAULT;
+
+ /*
+ * Init per tid tx state
+ */
+ for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno];
+ tidno < WME_NUM_TID;
+ tidno++, tid++) {
+ tid->an = an;
+ tid->tidno = tidno;
+ tid->seq_start = tid->seq_next = 0;
+ tid->baw_size = WME_MAX_BA;
+ tid->baw_head = tid->baw_tail = 0;
+ tid->sched = false;
+ tid->paused = false;
+ tid->cleanup_inprogress = false;
+ INIT_LIST_HEAD(&tid->buf_q);
+
+ acno = TID_TO_WME_AC(tidno);
+ tid->ac = &an->an_aggr.tx.ac[acno];
+
+ /* ADDBA state */
+ tid->addba_exchangecomplete = 0;
+ tid->addba_exchangeinprogress = 0;
+ tid->addba_exchangeattempts = 0;
+ }
+
+ /*
+ * Init per ac tx state
+ */
+ for (acno = 0, ac = &an->an_aggr.tx.ac[acno];
+ acno < WME_NUM_AC; acno++, ac++) {
+ ac->sched = false;
+ INIT_LIST_HEAD(&ac->tid_q);
+
+ switch (acno) {
+ case WME_AC_BE:
+ ac->qnum = ath_tx_get_qnum(sc,
+ ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+ break;
+ case WME_AC_BK:
+ ac->qnum = ath_tx_get_qnum(sc,
+ ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK);
+ break;
+ case WME_AC_VI:
+ ac->qnum = ath_tx_get_qnum(sc,
+ ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI);
+ break;
+ case WME_AC_VO:
+ ac->qnum = ath_tx_get_qnum(sc,
+ ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO);
+ break;
+ }
+ }
+ }
+}
+
+/* Cleanupthe pending buffers for the node. */
+
+void ath_tx_node_cleanup(struct ath_softc *sc,
+ struct ath_node *an, bool bh_flag)
+{
+ int i;
+ struct ath_atx_ac *ac, *ac_tmp;
+ struct ath_atx_tid *tid, *tid_tmp;
+ struct ath_txq *txq;
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (ATH_TXQ_SETUP(sc, i)) {
+ txq = &sc->sc_txq[i];
+
+ if (likely(bh_flag))
+ spin_lock_bh(&txq->axq_lock);
+ else
+ spin_lock(&txq->axq_lock);
+
+ list_for_each_entry_safe(ac,
+ ac_tmp, &txq->axq_acq, list) {
+ tid = list_first_entry(&ac->tid_q,
+ struct ath_atx_tid, list);
+ if (tid && tid->an != an)
+ continue;
+ list_del(&ac->list);
+ ac->sched = false;
+
+ list_for_each_entry_safe(tid,
+ tid_tmp, &ac->tid_q, list) {
+ list_del(&tid->list);
+ tid->sched = false;
+ ath_tid_drain(sc, txq, tid, bh_flag);
+ tid->addba_exchangecomplete = 0;
+ tid->addba_exchangeattempts = 0;
+ tid->cleanup_inprogress = false;
+ }
+ }
+
+ if (likely(bh_flag))
+ spin_unlock_bh(&txq->axq_lock);
+ else
+ spin_unlock(&txq->axq_lock);
+ }
+ }
+}
+
+/* Cleanup per node transmit state */
+
+void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an)
+{
+ if (sc->sc_txaggr) {
+ struct ath_atx_tid *tid;
+ int tidno, i;
+
+ /* Init per tid rx state */
+ for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno];
+ tidno < WME_NUM_TID;
+ tidno++, tid++) {
+
+ for (i = 0; i < ATH_TID_MAX_BUFS; i++)
+ ASSERT(tid->tx_buf[i] == NULL);
+ }
+ }
+}
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index bd35bb0a148..bd65c485098 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -1304,7 +1304,7 @@ EXPORT_SYMBOL(atmel_open);
int atmel_open(struct net_device *dev)
{
struct atmel_private *priv = netdev_priv(dev);
- int i, channel;
+ int i, channel, err;
/* any scheduled timer is no longer needed and might screw things up.. */
del_timer_sync(&priv->management_timer);
@@ -1328,8 +1328,9 @@ int atmel_open(struct net_device *dev)
priv->site_survey_state = SITE_SURVEY_IDLE;
priv->station_is_associated = 0;
- if (!reset_atmel_card(dev))
- return -EAGAIN;
+ err = reset_atmel_card(dev);
+ if (err)
+ return err;
if (priv->config_reg_domain) {
priv->reg_domain = priv->config_reg_domain;
@@ -3061,12 +3062,20 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
}
if (status == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
- /* Do opensystem first, then try sharedkey */
+ /* Flip back and forth between WEP auth modes until the max
+ * authentication tries has been exceeded.
+ */
if (system == WLAN_AUTH_OPEN) {
priv->CurrentAuthentTransactionSeqNum = 0x001;
priv->exclude_unencrypted = 1;
send_authentication_request(priv, WLAN_AUTH_SHARED_KEY, NULL, 0);
return;
+ } else if ( system == WLAN_AUTH_SHARED_KEY
+ && priv->wep_is_on) {
+ priv->CurrentAuthentTransactionSeqNum = 0x001;
+ priv->exclude_unencrypted = 0;
+ send_authentication_request(priv, WLAN_AUTH_OPEN, NULL, 0);
+ return;
} else if (priv->connect_to_any_BSS) {
int bss_index;
@@ -3580,12 +3589,12 @@ static int atmel_wakeup_firmware(struct atmel_private *priv)
if (i == 0) {
printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name);
- return 0;
+ return -EIO;
}
if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) {
printk(KERN_ALERT "%s: card missing.\n", priv->dev->name);
- return 0;
+ return -ENODEV;
}
/* now check for completion of MAC initialization through
@@ -3609,19 +3618,19 @@ static int atmel_wakeup_firmware(struct atmel_private *priv)
if (i == 0) {
printk(KERN_ALERT "%s: MAC failed to initialise.\n",
priv->dev->name);
- return 0;
+ return -EIO;
}
/* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */
if ((mr3 & MAC_INIT_COMPLETE) &&
!(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) {
printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name);
- return 0;
+ return -EIO;
}
if ((mr1 & MAC_INIT_COMPLETE) &&
!(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) {
printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name);
- return 0;
+ return -EIO;
}
atmel_copy_to_host(priv->dev, (unsigned char *)iface,
@@ -3642,7 +3651,7 @@ static int atmel_wakeup_firmware(struct atmel_private *priv)
iface->func_ctrl = le16_to_cpu(iface->func_ctrl);
iface->mac_status = le16_to_cpu(iface->mac_status);
- return 1;
+ return 0;
}
/* determine type of memory and MAC address */
@@ -3693,7 +3702,7 @@ static int probe_atmel_card(struct net_device *dev)
/* Standard firmware in flash, boot it up and ask
for the Mac Address */
priv->card_type = CARD_TYPE_SPI_FLASH;
- if (atmel_wakeup_firmware(priv)) {
+ if (atmel_wakeup_firmware(priv) == 0) {
atmel_get_mib(priv, Mac_Address_Mib_Type, 0, dev->dev_addr, 6);
/* got address, now squash it again until the network
@@ -3835,6 +3844,7 @@ static int reset_atmel_card(struct net_device *dev)
struct atmel_private *priv = netdev_priv(dev);
u8 configuration;
int old_state = priv->station_state;
+ int err = 0;
/* data to add to the firmware names, in priority order
this implemenents firmware versioning */
@@ -3868,11 +3878,12 @@ static int reset_atmel_card(struct net_device *dev)
dev->name);
strcpy(priv->firmware_id, "atmel_at76c502.bin");
}
- if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) != 0) {
+ err = request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev);
+ if (err != 0) {
printk(KERN_ALERT
"%s: firmware %s is missing, cannot continue.\n",
dev->name, priv->firmware_id);
- return 0;
+ return err;
}
} else {
int fw_index = 0;
@@ -3901,7 +3912,7 @@ static int reset_atmel_card(struct net_device *dev)
"%s: firmware %s is missing, cannot start.\n",
dev->name, priv->firmware_id);
priv->firmware_id[0] = '\0';
- return 0;
+ return -ENOENT;
}
}
@@ -3926,8 +3937,9 @@ static int reset_atmel_card(struct net_device *dev)
release_firmware(fw_entry);
}
- if (!atmel_wakeup_firmware(priv))
- return 0;
+ err = atmel_wakeup_firmware(priv);
+ if (err != 0)
+ return err;
/* Check the version and set the correct flag for wpa stuff,
old and new firmware is incompatible.
@@ -3968,10 +3980,9 @@ static int reset_atmel_card(struct net_device *dev)
if (!priv->radio_on_broken) {
if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) ==
CMD_STATUS_REJECTED_RADIO_OFF) {
- printk(KERN_INFO
- "%s: cannot turn the radio on. (Hey radio, you're beautiful!)\n",
+ printk(KERN_INFO "%s: cannot turn the radio on.\n",
dev->name);
- return 0;
+ return -EIO;
}
}
@@ -4006,7 +4017,7 @@ static int reset_atmel_card(struct net_device *dev)
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
}
- return 1;
+ return 0;
}
static void atmel_send_command(struct atmel_private *priv, int command,
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index e78319aa47c..7205a936ec7 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -33,7 +33,6 @@
#include <linux/moduleparam.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
-#include <linux/version.h>
#include <linux/firmware.h>
#include <linux/wireless.h>
#include <linux/workqueue.h>
@@ -4615,7 +4614,9 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
if (bus->bustype == SSB_BUSTYPE_PCI) {
pdev = bus->host_pci;
if (IS_PDEV(pdev, BROADCOM, 0x4318, ASUSTEK, 0x100F) ||
+ IS_PDEV(pdev, BROADCOM, 0x4320, DELL, 0x0003) ||
IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0015) ||
+ IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0014) ||
IS_PDEV(pdev, BROADCOM, 0x4320, LINKSYS, 0x0013))
bus->sprom.boardflags_lo &= ~B43_BFL_BTCOEXIST;
}
@@ -4645,8 +4646,7 @@ static int b43_wireless_init(struct ssb_device *dev)
}
/* fill hw info */
- hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
- IEEE80211_HW_RX_INCLUDES_FCS |
+ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
index fec5645944a..34ae125d538 100644
--- a/drivers/net/wireless/b43/rfkill.c
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -43,23 +43,6 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
return 0;
}
-/* Update the rfkill state */
-static void b43_rfkill_update_state(struct b43_wldev *dev)
-{
- struct b43_rfkill *rfk = &(dev->wl->rfkill);
-
- if (!dev->radio_hw_enable) {
- rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED;
- return;
- }
-
- if (!dev->phy.radio_on)
- rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED;
- else
- rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
-
-}
-
/* The poll callback for the hardware button. */
static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
{
@@ -77,7 +60,6 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
if (unlikely(enabled != dev->radio_hw_enable)) {
dev->radio_hw_enable = enabled;
report_change = 1;
- b43_rfkill_update_state(dev);
b43info(wl, "Radio hardware status changed to %s\n",
enabled ? "ENABLED" : "DISABLED");
}
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 8d54502222a..9dda8169f7c 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -192,7 +192,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
const struct b43_phy *phy = &dev->phy;
const struct ieee80211_hdr *wlhdr =
(const struct ieee80211_hdr *)fragment_data;
- int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
+ int use_encryption = !!info->control.hw_key;
__le16 fctl = wlhdr->frame_control;
struct ieee80211_rate *fbrate;
u8 rate, rate_fb;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index a1b8bf3ee73..1cb77db5c29 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -34,7 +34,6 @@
#include <linux/moduleparam.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
-#include <linux/version.h>
#include <linux/firmware.h>
#include <linux/wireless.h>
#include <linux/workqueue.h>
@@ -3702,8 +3701,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
}
/* fill hw info */
- hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
- IEEE80211_HW_RX_INCLUDES_FCS |
+ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
hw->queues = 1; /* FIXME: hardware has more queues */
@@ -3846,10 +3844,10 @@ static int b43legacy_resume(struct ssb_device *dev)
goto out;
}
}
- mutex_unlock(&wl->mutex);
b43legacydbg(wl, "Device resumed.\n");
out:
+ mutex_unlock(&wl->mutex);
return err;
}
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c
index 476add97e97..b32bf6a94f1 100644
--- a/drivers/net/wireless/b43legacy/rfkill.c
+++ b/drivers/net/wireless/b43legacy/rfkill.c
@@ -44,23 +44,6 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
return 0;
}
-/* Update the rfkill state */
-static void b43legacy_rfkill_update_state(struct b43legacy_wldev *dev)
-{
- struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
-
- if (!dev->radio_hw_enable) {
- rfk->rfkill->state = RFKILL_STATE_HARD_BLOCKED;
- return;
- }
-
- if (!dev->phy.radio_on)
- rfk->rfkill->state = RFKILL_STATE_SOFT_BLOCKED;
- else
- rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
-
-}
-
/* The poll callback for the hardware button. */
static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
{
@@ -78,7 +61,6 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
if (unlikely(enabled != dev->radio_hw_enable)) {
dev->radio_hw_enable = enabled;
report_change = 1;
- b43legacy_rfkill_update_state(dev);
b43legacyinfo(wl, "Radio hardware status changed to %s\n",
enabled ? "ENABLED" : "DISABLED");
}
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index e969ed8d412..68e1f8c7872 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -192,7 +192,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
u16 cookie)
{
const struct ieee80211_hdr *wlhdr;
- int use_encryption = (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT));
+ int use_encryption = !!info->control.hw_key;
u16 fctl;
u8 rate;
struct ieee80211_rate *rate_fb;
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 5bf9e00b070..19a401c4a0d 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -157,7 +157,6 @@ that only one external action is invoked at a time.
#include <linux/stringify.h>
#include <linux/tcp.h>
#include <linux/types.h>
-#include <linux/version.h>
#include <linux/time.h>
#include <linux/firmware.h>
#include <linux/acpi.h>
@@ -6442,6 +6441,7 @@ static int ipw2100_resume(struct pci_dev *pci_dev)
if (err) {
printk(KERN_ERR "%s: pci_enable_device failed on resume\n",
dev->name);
+ mutex_unlock(&priv->action_mutex);
return err;
}
pci_restore_state(pci_dev);
@@ -7146,7 +7146,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev,
err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
if (err) {
IPW_DEBUG_WX("failed querying ordinals.\n");
- return err;
+ goto done;
}
switch (val & TX_RATE_MASK) {
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 1acfbcd3703..dcce3542d5a 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -31,7 +31,6 @@
******************************************************************************/
#include "ipw2200.h"
-#include <linux/version.h>
#ifndef KBUILD_EXTMOD
@@ -305,9 +304,10 @@ static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c)
#define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs))
/* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write8(ipw, ofs, val) \
+#define ipw_write8(ipw, ofs, val) do { \
IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write8(ipw, ofs, val)
+ _ipw_write8(ipw, ofs, val); \
+ } while (0)
/* 16-bit direct write (low 4K) */
#define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs))
@@ -11946,7 +11946,7 @@ module_param(auto_create, int, 0444);
MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
module_param(led, int, 0444);
-MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)\n");
+MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)");
module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 82b66a3d3a5..b0ac0ce3fb9 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -14,18 +14,49 @@ config IWLWIFI_LEDS
default n
config IWLWIFI_RFKILL
- boolean "IWLWIFI RF kill support"
+ boolean "Iwlwifi RF kill support"
depends on IWLCORE
-config IWL4965
- tristate "Intel Wireless WiFi 4965AGN"
+config IWLWIFI_DEBUG
+ bool "Enable full debugging output in iwlagn driver"
+ depends on IWLCORE
+ ---help---
+ This option will enable debug tracing output for the iwlwifi drivers
+
+ This will result in the kernel module being ~100k larger. You can
+ control which debug output is sent to the kernel log by setting the
+ value in
+
+ /sys/class/net/wlan0/device/debug_level
+
+ This entry will only exist if this option is enabled.
+
+ To set a value, simply echo an 8-byte hex value to the same file:
+
+ % echo 0x43fff > /sys/class/net/wlan0/device/debug_level
+
+ You can find the list of debug mask values in:
+ drivers/net/wireless/iwlwifi/iwl-debug.h
+
+ If this is your first time using this driver, you should say Y here
+ as the debug information can assist others in helping you resolve
+ any problems you may encounter.
+
+config IWLWIFI_DEBUGFS
+ bool "Iwlwifi debugfs support"
+ depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS
+ ---help---
+ Enable creation of debugfs files for the iwlwifi drivers.
+
+config IWLAGN
+ tristate "Intel Wireless WiFi Next Gen AGN"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select FW_LOADER
select IWLCORE
---help---
Select to build the driver supporting the:
- Intel Wireless WiFi Link 4965AGN
+ Intel Wireless WiFi Link Next-Gen AGN
This driver uses the kernel's mac80211 subsystem.
@@ -42,60 +73,33 @@ config IWL4965
If you want to compile the driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/kbuild/modules.txt>. The
- module will be called iwl4965.ko.
-
-config IWL4965_LEDS
- bool "Enable LEDS features in iwl4965 driver"
- depends on IWL4965
- select IWLWIFI_LEDS
- ---help---
- This option enables LEDS for the iwlwifi drivers
+ module will be called iwlagn.ko.
-
-config IWL4965_SPECTRUM_MEASUREMENT
- bool "Enable Spectrum Measurement in iwl4965 driver"
- depends on IWL4965
+config IWLAGN_SPECTRUM_MEASUREMENT
+ bool "Enable Spectrum Measurement in iwlagn driver"
+ depends on IWLAGN
---help---
- This option will enable spectrum measurement for the iwl4965 driver.
+ This option will enable spectrum measurement for the iwlagn driver.
-config IWLWIFI_DEBUG
- bool "Enable full debugging output in iwl4965 driver"
- depends on IWL4965
+config IWLAGN_LEDS
+ bool "Enable LEDS features in iwlagn driver"
+ depends on IWLAGN
+ select IWLWIFI_LEDS
---help---
- This option will enable debug tracing output for the iwl4965
- driver.
-
- This will result in the kernel module being ~100k larger. You can
- control which debug output is sent to the kernel log by setting the
- value in
-
- /sys/class/net/wlan0/device/debug_level
-
- This entry will only exist if this option is enabled.
-
- To set a value, simply echo an 8-byte hex value to the same file:
-
- % echo 0x43fff > /sys/class/net/wlan0/device/debug_level
+ This option enables LEDS for the iwlagn drivers
- You can find the list of debug mask values in:
- drivers/net/wireless/iwlwifi/iwl-4965-debug.h
- If this is your first time using this driver, you should say Y here
- as the debug information can assist others in helping you resolve
- any problems you may encounter.
+config IWL4965
+ bool "Intel Wireless WiFi 4965AGN"
+ depends on IWLAGN
+ ---help---
+ This option enables support for Intel Wireless WiFi Link 4965AGN
config IWL5000
bool "Intel Wireless WiFi 5000AGN"
- depends on IWL4965
+ depends on IWLAGN
---help---
This option enables support for Intel Wireless WiFi Link 5000AGN Family
- Dependency on 4965 is temporary
-
-config IWLWIFI_DEBUGFS
- bool "Iwlwifi debugfs support"
- depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS
- ---help---
- Enable creation of debugfs files for the iwlwifi drivers.
config IWL3945
tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 1f52b92f08b..47aa28f6a51 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -6,15 +6,14 @@ iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o
+obj-$(CONFIG_IWLAGN) += iwlagn.o
+iwlagn-objs := iwl-agn.o iwl-agn-rs.o
+
+iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
+iwlagn-$(CONFIG_IWL5000) += iwl-5000.o
+
obj-$(CONFIG_IWL3945) += iwl3945.o
iwl3945-objs := iwl3945-base.o iwl-3945.o iwl-3945-rs.o
iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o
-obj-$(CONFIG_IWL4965) += iwl4965.o
-iwl4965-objs := iwl4965-base.o iwl-4965.o iwl-4965-rs.o
-
-ifeq ($(CONFIG_IWL5000),y)
- iwl4965-objs += iwl-5000.o
-endif
-
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
index 6be1fe13fa5..705c65bed9f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
@@ -206,12 +205,12 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev,
static int iwl3945_led_register_led(struct iwl3945_priv *priv,
struct iwl3945_led *led,
enum led_type type, u8 set_led,
- const char *name, char *trigger)
+ char *trigger)
{
struct device *device = wiphy_dev(priv->hw->wiphy);
int ret;
- led->led_dev.name = name;
+ led->led_dev.name = led->name;
led->led_dev.brightness_set = iwl3945_led_brightness_set;
led->led_dev.default_trigger = trigger;
@@ -308,7 +307,6 @@ void iwl3945_led_background(struct iwl3945_priv *priv)
int iwl3945_led_register(struct iwl3945_priv *priv)
{
char *trigger;
- char name[32];
int ret;
priv->last_blink_rate = 0;
@@ -318,7 +316,8 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
priv->allow_blinking = 0;
trigger = ieee80211_get_radio_led_name(priv->hw);
- snprintf(name, sizeof(name), "iwl-%s:radio",
+ snprintf(priv->led[IWL_LED_TRG_RADIO].name,
+ sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s:radio",
wiphy_name(priv->hw->wiphy));
priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on;
@@ -327,19 +326,20 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
ret = iwl3945_led_register_led(priv,
&priv->led[IWL_LED_TRG_RADIO],
- IWL_LED_TRG_RADIO, 1,
- name, trigger);
+ IWL_LED_TRG_RADIO, 1, trigger);
+
if (ret)
goto exit_fail;
trigger = ieee80211_get_assoc_led_name(priv->hw);
- snprintf(name, sizeof(name), "iwl-%s:assoc",
+ snprintf(priv->led[IWL_LED_TRG_ASSOC].name,
+ sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s:assoc",
wiphy_name(priv->hw->wiphy));
ret = iwl3945_led_register_led(priv,
&priv->led[IWL_LED_TRG_ASSOC],
- IWL_LED_TRG_ASSOC, 0,
- name, trigger);
+ IWL_LED_TRG_ASSOC, 0, trigger);
+
/* for assoc always turn led on */
priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on;
priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on;
@@ -349,14 +349,13 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
goto exit_fail;
trigger = ieee80211_get_rx_led_name(priv->hw);
- snprintf(name, sizeof(name), "iwl-%s:RX",
+ snprintf(priv->led[IWL_LED_TRG_RX].name,
+ sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s:RX",
wiphy_name(priv->hw->wiphy));
-
ret = iwl3945_led_register_led(priv,
&priv->led[IWL_LED_TRG_RX],
- IWL_LED_TRG_RX, 0,
- name, trigger);
+ IWL_LED_TRG_RX, 0, trigger);
priv->led[IWL_LED_TRG_RX].led_on = iwl3945_led_associated;
priv->led[IWL_LED_TRG_RX].led_off = iwl3945_led_associated;
@@ -366,13 +365,14 @@ int iwl3945_led_register(struct iwl3945_priv *priv)
goto exit_fail;
trigger = ieee80211_get_tx_led_name(priv->hw);
- snprintf(name, sizeof(name), "iwl-%s:TX",
+ snprintf(priv->led[IWL_LED_TRG_TX].name,
+ sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s:TX",
wiphy_name(priv->hw->wiphy));
ret = iwl3945_led_register_led(priv,
&priv->led[IWL_LED_TRG_TX],
- IWL_LED_TRG_TX, 0,
- name, trigger);
+ IWL_LED_TRG_TX, 0, trigger);
+
priv->led[IWL_LED_TRG_TX].led_on = iwl3945_led_associated;
priv->led[IWL_LED_TRG_TX].led_off = iwl3945_led_associated;
priv->led[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
index 47b7e0bac80..2fbd126c134 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
@@ -50,6 +50,7 @@ enum led_type {
struct iwl3945_led {
struct iwl3945_priv *priv;
struct led_classdev led_dev;
+ char name[32];
int (*led_on) (struct iwl3945_priv *priv, int led_id);
int (*led_off) (struct iwl3945_priv *priv, int led_id);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index c2a76785b66..3f51f363534 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
@@ -630,7 +629,9 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl3945_priv *priv,
struct ieee80211_rx_status *stats)
{
struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data;
+#ifdef CONFIG_IWL3945_LEDS
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
+#endif
struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
short len = le16_to_cpu(rx_hdr->len);
@@ -708,10 +709,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
return;
}
- if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
- iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
- return;
- }
+
/* Convert 3945's rssi indicator to dBm */
rx_status.signal = rx_stats->rssi - IWL_RSSI_OFFSET;
@@ -773,6 +771,11 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
priv->last_rx_noise = rx_status.noise;
}
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
+ return;
+ }
+
switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {
case IEEE80211_FTYPE_MGMT:
switch (le16_to_cpu(header->frame_control) &
@@ -791,8 +794,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
struct ieee80211_mgmt *mgmt =
(struct ieee80211_mgmt *)header;
__le32 *pos;
- pos =
- (__le32 *) & mgmt->u.beacon.
+ pos = (__le32 *)&mgmt->u.beacon.
timestamp;
priv->timestamp0 = le32_to_cpu(pos[0]);
priv->timestamp1 = le32_to_cpu(pos[1]);
@@ -1505,7 +1507,7 @@ static int iwl3945_hw_reg_adjust_power_by_temp(int new_reading, int old_reading)
*/
static inline int iwl3945_hw_reg_temp_out_of_range(int temperature)
{
- return (((temperature < -260) || (temperature > 25)) ? 1 : 0);
+ return ((temperature < -260) || (temperature > 25)) ? 1 : 0;
}
int iwl3945_hw_get_temperature(struct iwl3945_priv *priv)
@@ -2626,7 +2628,7 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv,
tx_beacon_cmd->tx.supp_rates[1] =
(IWL_CCK_BASIC_RATES_MASK & 0xF);
- return (sizeof(struct iwl3945_tx_beacon_cmd) + frame_size);
+ return sizeof(struct iwl3945_tx_beacon_cmd) + frame_size;
}
void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv)
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 9afecb81371..23fed329896 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
@@ -341,39 +340,6 @@ err:
return -EINVAL;
}
-int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
-{
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- ret = iwl_grab_nic_access(priv);
- if (ret) {
- spin_unlock_irqrestore(&priv->lock, flags);
- return ret;
- }
-
- if (src == IWL_PWR_SRC_VAUX) {
- u32 val;
- ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
- &val);
-
- if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
- iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
- ~APMG_PS_CTRL_MSK_PWR_SRC);
- }
- } else {
- iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
- APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
- ~APMG_PS_CTRL_MSK_PWR_SRC);
- }
-
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return ret;
-}
/*
* Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask
@@ -508,8 +474,8 @@ static void iwl4965_apm_stop(struct iwl_priv *priv)
iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
udelay(10);
-
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ /* clear "init complete" move adapter D0A* --> D0U state */
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -875,18 +841,6 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
return 0;
}
-/* set card power command */
-static int iwl4965_set_power(struct iwl_priv *priv,
- void *cmd)
-{
- int ret = 0;
-
- ret = iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD,
- sizeof(struct iwl4965_powertable_cmd),
- cmd, NULL);
- return ret;
-}
-
static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res)
{
s32 sign = 1;
@@ -1012,7 +966,7 @@ static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,
s = iwl4965_get_sub_band(priv, channel);
if (s >= EEPROM_TX_POWER_BANDS) {
- IWL_ERROR("Tx Power can not find channel %d ", channel);
+ IWL_ERROR("Tx Power can not find channel %d\n", channel);
return -1;
}
@@ -1560,11 +1514,11 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
c, atten_value, power_index,
tx_power.s.radio_tx_gain[c],
tx_power.s.dsp_predis_atten[c]);
- }/* for each chain */
+ } /* for each chain */
tx_power_tbl->power_tbl[i].dw = cpu_to_le32(tx_power.dw);
- }/* for each rate */
+ } /* for each rate */
return 0;
}
@@ -1701,38 +1655,6 @@ static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv)
return le32_to_cpu(s->rb_closed) & 0xFFF;
}
-unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
- struct iwl_frame *frame, u8 rate)
-{
- struct iwl4965_tx_beacon_cmd *tx_beacon_cmd;
- unsigned int frame_size;
-
- tx_beacon_cmd = &frame->u.beacon;
- memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
-
- tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
- tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-
- frame_size = iwl4965_fill_beacon_frame(priv,
- tx_beacon_cmd->frame,
- iwl_bcast_addr,
- sizeof(frame->u) - sizeof(*tx_beacon_cmd));
-
- BUG_ON(frame_size > MAX_MPDU_SIZE);
- tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
-
- if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
- tx_beacon_cmd->tx.rate_n_flags =
- iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
- else
- tx_beacon_cmd->tx.rate_n_flags =
- iwl_hw_set_rate_n_flags(rate, 0);
-
- tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK |
- TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK);
- return (sizeof(*tx_beacon_cmd) + frame_size);
-}
-
static int iwl4965_alloc_shared_mem(struct iwl_priv *priv)
{
priv->shared_virt = pci_alloc_consistent(priv->pci_dev,
@@ -2079,39 +2001,6 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id,
return 0;
}
-int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
- enum ieee80211_ampdu_mlme_action action,
- const u8 *addr, u16 tid, u16 *ssn)
-{
- struct iwl_priv *priv = hw->priv;
- DECLARE_MAC_BUF(mac);
-
- IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n",
- print_mac(mac, addr), tid);
-
- if (!(priv->cfg->sku & IWL_SKU_N))
- return -EACCES;
-
- switch (action) {
- case IEEE80211_AMPDU_RX_START:
- IWL_DEBUG_HT("start Rx\n");
- return iwl_rx_agg_start(priv, addr, tid, *ssn);
- case IEEE80211_AMPDU_RX_STOP:
- IWL_DEBUG_HT("stop Rx\n");
- return iwl_rx_agg_stop(priv, addr, tid);
- case IEEE80211_AMPDU_TX_START:
- IWL_DEBUG_HT("start Tx\n");
- return iwl_tx_agg_start(priv, addr, tid, ssn);
- case IEEE80211_AMPDU_TX_STOP:
- IWL_DEBUG_HT("stop Tx\n");
- return iwl_tx_agg_stop(priv, addr, tid);
- default:
- IWL_DEBUG_HT("unknown\n");
- return -EINVAL;
- break;
- }
- return 0;
-}
static u16 iwl4965_get_hcmd_size(u8 cmd_id, u16 len)
{
@@ -2240,9 +2129,9 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
bitmap = bitmap << sh;
sh = 0;
}
- bitmap |= (1 << sh);
- IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
- start, (u32)(bitmap & 0xFFFFFFFF));
+ bitmap |= 1ULL << sh;
+ IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%llx\n",
+ start, (unsigned long long)bitmap);
}
agg->bitmap = bitmap;
@@ -2368,6 +2257,40 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
}
+static int iwl4965_calc_rssi(struct iwl_priv *priv,
+ struct iwl_rx_phy_res *rx_resp)
+{
+ /* data from PHY/DSP regarding signal strength, etc.,
+ * contents are always there, not configurable by host. */
+ struct iwl4965_rx_non_cfg_phy *ncphy =
+ (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
+ u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL49_AGC_DB_MASK)
+ >> IWL49_AGC_DB_POS;
+
+ u32 valid_antennae =
+ (le16_to_cpu(rx_resp->phy_flags) & IWL49_RX_PHY_FLAGS_ANTENNAE_MASK)
+ >> IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET;
+ u8 max_rssi = 0;
+ u32 i;
+
+ /* Find max rssi among 3 possible receivers.
+ * These values are measured by the digital signal processor (DSP).
+ * They should stay fairly constant even as the signal strength varies,
+ * if the radio's automatic gain control (AGC) is working right.
+ * AGC value (see below) will provide the "interesting" info. */
+ for (i = 0; i < 3; i++)
+ if (valid_antennae & (1 << i))
+ max_rssi = max(ncphy->rssi_info[i << 1], max_rssi);
+
+ IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+ ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4],
+ max_rssi, agc);
+
+ /* dBm = max_rssi dB - agc dB - constant.
+ * Higher AGC (higher radio gain) means lower signal. */
+ return max_rssi - agc - IWL_RSSI_OFFSET;
+}
+
/* Set up 4965-specific Rx frame reply handlers */
static void iwl4965_rx_handler_setup(struct iwl_priv *priv)
@@ -2399,6 +2322,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.chain_noise_reset = iwl4965_chain_noise_reset,
.gain_computation = iwl4965_gain_computation,
.rts_tx_cmd_flag = iwl4965_rts_tx_cmd_flag,
+ .calc_rssi = iwl4965_calc_rssi,
};
static struct iwl_lib_ops iwl4965_lib = {
@@ -2440,7 +2364,6 @@ static struct iwl_lib_ops iwl4965_lib = {
.check_version = iwl4965_eeprom_check_version,
.query_addr = iwlcore_eeprom_query_addr,
},
- .set_power = iwl4965_set_power,
.send_tx_power = iwl4965_send_tx_power,
.update_chain_flags = iwl4965_update_chain_flags,
.temperature = iwl4965_temperature_calib,
@@ -2469,7 +2392,7 @@ MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(disable, iwl4965_mod_params.disable, int, 0444);
MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
-MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])\n");
+MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
module_param_named(debug, iwl4965_mod_params.debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
module_param_named(
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 878d6193b23..b08036a9d89 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
@@ -93,6 +92,13 @@ static int iwl5000_apm_init(struct iwl_priv *priv)
iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
+ /* Set FH wait treshold to maximum (HW error during stress W/A) */
+ iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
+
+ /* enable HAP INTA to move device L1a -> L0s */
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
+
iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL);
/* set "initialization complete" bit to move adapter
@@ -139,7 +145,8 @@ static void iwl5000_apm_stop(struct iwl_priv *priv)
udelay(10);
- iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ /* clear "init complete" move adapter D0A* --> D0U state */
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -230,6 +237,16 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
+ /* W/A : NIC is stuck in a reset state after Early PCIe power off
+ * (PCIe power is lost before PERST# is asserted),
+ * causing ME FW to lose ownership and not being able to obtain it back.
+ */
+ iwl_grab_nic_access(priv);
+ iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
+ ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+ iwl_release_nic_access(priv);
+
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -561,14 +578,11 @@ static int iwl5000_load_section(struct iwl_priv *priv,
FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
- /* FIME: write the MSB of the phy_addr in CTRL1
- * iwl_write_direct32(priv,
- IWL_FH_TFDIB_CTRL1_REG(IWL_FH_SRVC_CHNL),
- ((phy_addr & MSB_MSK)
- << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_count);
- */
iwl_write_direct32(priv,
- FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), byte_cnt);
+ FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
+ (iwl_get_dma_hi_address(phy_addr)
+ << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
+
iwl_write_direct32(priv,
FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
@@ -924,8 +938,8 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
if (txq_id != IWL_CMD_QUEUE_NUM) {
- sta = txq->cmd[txq->q.write_ptr].cmd.tx.sta_id;
- sec_ctl = txq->cmd[txq->q.write_ptr].cmd.tx.sec_ctl;
+ sta = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
+ sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
switch (sec_ctl & TX_CMD_SEC_MSK) {
case TX_CMD_SEC_CCM:
@@ -964,7 +978,7 @@ static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
u8 sta = 0;
if (txq_id != IWL_CMD_QUEUE_NUM)
- sta = txq->cmd[txq->q.read_ptr].cmd.tx.sta_id;
+ sta = txq->cmd[txq->q.read_ptr]->cmd.tx.sta_id;
shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr].
val = cpu_to_le16(1 | (sta << 12));
@@ -1131,7 +1145,7 @@ static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
static inline u32 iwl5000_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
{
- return le32_to_cpup((__le32*)&tx_resp->status +
+ return le32_to_cpup((__le32 *)&tx_resp->status +
tx_resp->frame_count) & MAX_SN;
}
@@ -1228,9 +1242,9 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
bitmap = bitmap << sh;
sh = 0;
}
- bitmap |= (1 << sh);
- IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
- start, (u32)(bitmap & 0xFFFFFFFF));
+ bitmap |= 1ULL << sh;
+ IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%llx\n",
+ start, (unsigned long long)bitmap);
}
agg->bitmap = bitmap;
@@ -1444,6 +1458,44 @@ static void iwl5000_temperature(struct iwl_priv *priv)
priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
}
+/* Calc max signal level (dBm) among 3 possible receivers */
+static int iwl5000_calc_rssi(struct iwl_priv *priv,
+ struct iwl_rx_phy_res *rx_resp)
+{
+ /* data from PHY/DSP regarding signal strength, etc.,
+ * contents are always there, not configurable by host
+ */
+ struct iwl5000_non_cfg_phy *ncphy =
+ (struct iwl5000_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
+ u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
+ u8 agc;
+
+ val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_AGC_IDX]);
+ agc = (val & IWL50_OFDM_AGC_MSK) >> IWL50_OFDM_AGC_BIT_POS;
+
+ /* Find max rssi among 3 possible receivers.
+ * These values are measured by the digital signal processor (DSP).
+ * They should stay fairly constant even as the signal strength varies,
+ * if the radio's automatic gain control (AGC) is working right.
+ * AGC value (see below) will provide the "interesting" info.
+ */
+ val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_AB_IDX]);
+ rssi_a = (val & IWL50_OFDM_RSSI_A_MSK) >> IWL50_OFDM_RSSI_A_BIT_POS;
+ rssi_b = (val & IWL50_OFDM_RSSI_B_MSK) >> IWL50_OFDM_RSSI_B_BIT_POS;
+ val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_C_IDX]);
+ rssi_c = (val & IWL50_OFDM_RSSI_C_MSK) >> IWL50_OFDM_RSSI_C_BIT_POS;
+
+ max_rssi = max_t(u32, rssi_a, rssi_b);
+ max_rssi = max_t(u32, max_rssi, rssi_c);
+
+ IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+ rssi_a, rssi_b, rssi_c, max_rssi, agc);
+
+ /* dBm = max_rssi dB - agc dB - constant.
+ * Higher AGC (higher radio gain) means lower signal. */
+ return max_rssi - agc - IWL_RSSI_OFFSET;
+}
+
static struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc,
};
@@ -1454,6 +1506,7 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
.gain_computation = iwl5000_gain_computation,
.chain_noise_reset = iwl5000_chain_noise_reset,
.rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
+ .calc_rssi = iwl5000_calc_rssi,
};
static struct iwl_lib_ops iwl5000_lib = {
@@ -1474,6 +1527,7 @@ static struct iwl_lib_ops iwl5000_lib = {
.alive_notify = iwl5000_alive_notify,
.send_tx_power = iwl5000_send_tx_power,
.temperature = iwl5000_temperature,
+ .update_chain_flags = iwl4965_update_chain_flags,
.apm_ops = {
.init = iwl5000_apm_init,
.reset = iwl5000_apm_reset,
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 3ccb84aa5db..90a2b6dee7c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -42,7 +42,7 @@
#include "iwl-core.h"
#include "iwl-helpers.h"
-#define RS_NAME "iwl-4965-rs"
+#define RS_NAME "iwl-agn-rs"
#define NUM_TRY_BEFORE_ANT_TOGGLE 1
#define IWL_NUMBER_TRY 1
@@ -77,9 +77,9 @@ static const u8 ant_toggle_lookup[] = {
};
/**
- * struct iwl4965_rate_scale_data -- tx success history for one rate
+ * struct iwl_rate_scale_data -- tx success history for one rate
*/
-struct iwl4965_rate_scale_data {
+struct iwl_rate_scale_data {
u64 data; /* bitmap of successful frames */
s32 success_counter; /* number of frames successful */
s32 success_ratio; /* per-cent * 128 */
@@ -89,12 +89,12 @@ struct iwl4965_rate_scale_data {
};
/**
- * struct iwl4965_scale_tbl_info -- tx params and success history for all rates
+ * struct iwl_scale_tbl_info -- tx params and success history for all rates
*
- * There are two of these in struct iwl4965_lq_sta,
+ * There are two of these in struct iwl_lq_sta,
* one for "active", and one for "search".
*/
-struct iwl4965_scale_tbl_info {
+struct iwl_scale_tbl_info {
enum iwl_table_type lq_type;
u8 ant_type;
u8 is_SGI; /* 1 = short guard interval */
@@ -103,10 +103,10 @@ struct iwl4965_scale_tbl_info {
u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
u32 current_rate; /* rate_n_flags, uCode API format */
- struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
+ struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
};
-struct iwl4965_traffic_load {
+struct iwl_traffic_load {
unsigned long time_stamp; /* age of the oldest statistics */
u32 packet_count[TID_QUEUE_MAX_SIZE]; /* packet count in this time
* slice */
@@ -118,11 +118,11 @@ struct iwl4965_traffic_load {
};
/**
- * struct iwl4965_lq_sta -- driver's rate scaling private structure
+ * struct iwl_lq_sta -- driver's rate scaling private structure
*
* Pointer to this gets passed back and forth between driver and mac80211.
*/
-struct iwl4965_lq_sta {
+struct iwl_lq_sta {
u8 active_tbl; /* index of active table, range 0-1 */
u8 enable_counter; /* indicates HT mode */
u8 stay_in_tbl; /* 1: disallow, 0: allow search for new mode */
@@ -153,8 +153,8 @@ struct iwl4965_lq_sta {
u16 active_rate_basic;
struct iwl_link_quality_cmd lq;
- struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
- struct iwl4965_traffic_load load[TID_MAX_LOAD_COUNT];
+ struct iwl_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */
+ struct iwl_traffic_load load[TID_MAX_LOAD_COUNT];
u8 tx_agg_tid_en;
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *rs_sta_dbgfs_scale_table_file;
@@ -170,16 +170,15 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,
struct sta_info *sta);
static void rs_fill_link_cmd(const struct iwl_priv *priv,
- struct iwl4965_lq_sta *lq_sta,
- u32 rate_n_flags);
+ struct iwl_lq_sta *lq_sta, u32 rate_n_flags);
#ifdef CONFIG_MAC80211_DEBUGFS
-static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
- u32 *rate_n_flags, int index);
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+ u32 *rate_n_flags, int index);
#else
-static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
- u32 *rate_n_flags, int index)
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+ u32 *rate_n_flags, int index)
{}
#endif
@@ -234,7 +233,7 @@ static inline u8 rs_extract_rate(u32 rate_n_flags)
return (u8)(rate_n_flags & 0xFF);
}
-static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window)
+static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
{
window->data = 0;
window->success_counter = 0;
@@ -246,14 +245,14 @@ static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window)
static inline u8 rs_is_valid_ant(u8 valid_antenna, u8 ant_type)
{
- return ((ant_type & valid_antenna) == ant_type);
+ return (ant_type & valid_antenna) == ant_type;
}
/*
* removes the old data from the statistics. All data that is older than
* TID_MAX_TIME_DIFF, will be deleted.
*/
-static void rs_tl_rm_old_stats(struct iwl4965_traffic_load *tl, u32 curr_time)
+static void rs_tl_rm_old_stats(struct iwl_traffic_load *tl, u32 curr_time)
{
/* The oldest age we want to keep */
u32 oldest_time = curr_time - TID_MAX_TIME_DIFF;
@@ -274,13 +273,13 @@ static void rs_tl_rm_old_stats(struct iwl4965_traffic_load *tl, u32 curr_time)
* increment traffic load value for tid and also remove
* any old values if passed the certain time period
*/
-static u8 rs_tl_add_packet(struct iwl4965_lq_sta *lq_data,
+static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
struct ieee80211_hdr *hdr)
{
u32 curr_time = jiffies_to_msecs(jiffies);
u32 time_diff;
s32 index;
- struct iwl4965_traffic_load *tl = NULL;
+ struct iwl_traffic_load *tl = NULL;
__le16 fc = hdr->frame_control;
u8 tid;
@@ -325,12 +324,12 @@ static u8 rs_tl_add_packet(struct iwl4965_lq_sta *lq_data,
/*
get the traffic load value for tid
*/
-static u32 rs_tl_get_load(struct iwl4965_lq_sta *lq_data, u8 tid)
+static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid)
{
u32 curr_time = jiffies_to_msecs(jiffies);
u32 time_diff;
s32 index;
- struct iwl4965_traffic_load *tl = NULL;
+ struct iwl_traffic_load *tl = NULL;
if (tid >= TID_MAX_LOAD_COUNT)
return 0;
@@ -354,8 +353,8 @@ static u32 rs_tl_get_load(struct iwl4965_lq_sta *lq_data, u8 tid)
}
static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
- struct iwl4965_lq_sta *lq_data, u8 tid,
- struct sta_info *sta)
+ struct iwl_lq_sta *lq_data, u8 tid,
+ struct sta_info *sta)
{
unsigned long state;
DECLARE_MAC_BUF(mac);
@@ -373,8 +372,8 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
}
static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
- struct iwl4965_lq_sta *lq_data,
- struct sta_info *sta)
+ struct iwl_lq_sta *lq_data,
+ struct sta_info *sta)
{
if ((tid < TID_MAX_LOAD_COUNT))
rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
@@ -385,9 +384,9 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
{
- return (!!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
- !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
- !!(rate_n_flags & RATE_MCS_ANT_C_MSK));
+ return !!(rate_n_flags & RATE_MCS_ANT_A_MSK) +
+ !!(rate_n_flags & RATE_MCS_ANT_B_MSK) +
+ !!(rate_n_flags & RATE_MCS_ANT_C_MSK);
}
/**
@@ -397,11 +396,11 @@ static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
* at this rate. window->data contains the bitmask of successful
* packets.
*/
-static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows,
+static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
int scale_index, s32 tpt, int retries,
int successes)
{
- struct iwl4965_rate_scale_data *window = NULL;
+ struct iwl_rate_scale_data *window = NULL;
static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
s32 fail_count;
@@ -473,7 +472,7 @@ static int rs_collect_tx_data(struct iwl4965_rate_scale_data *windows,
* Fill uCode API rate_n_flags field, based on "search" or "active" table.
*/
/* FIXME:RS:remove this function and put the flags statically in the table */
-static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl,
+static u32 rate_n_flags_from_tbl(struct iwl_scale_tbl_info *tbl,
int index, u8 use_green)
{
u32 rate_n_flags = 0;
@@ -530,7 +529,7 @@ static u32 rate_n_flags_from_tbl(struct iwl4965_scale_tbl_info *tbl,
*/
static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
enum ieee80211_band band,
- struct iwl4965_scale_tbl_info *tbl,
+ struct iwl_scale_tbl_info *tbl,
int *rate_idx)
{
u32 ant_msk = (rate_n_flags & RATE_MCS_ANT_ABC_MSK);
@@ -591,7 +590,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
/* switch to another antenna/antennas and return 1 */
/* if no other valid antenna found, return 0 */
static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
- struct iwl4965_scale_tbl_info *tbl)
+ struct iwl_scale_tbl_info *tbl)
{
u8 new_ant_type;
@@ -621,9 +620,9 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
#if 0
static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf)
{
- return ((conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
+ return (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) &&
priv->current_ht_config.is_green_field &&
- !priv->current_ht_config.non_GF_STA_present);
+ !priv->current_ht_config.non_GF_STA_present;
}
#endif
static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf)
@@ -638,9 +637,9 @@ static inline u8 rs_use_green(struct iwl_priv *priv, struct ieee80211_conf *conf
* basic available rates.
*
*/
-static u16 rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta,
- struct ieee80211_hdr *hdr,
- enum iwl_table_type rate_type)
+static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
+ struct ieee80211_hdr *hdr,
+ enum iwl_table_type rate_type)
{
if (hdr && is_multicast_ether_addr(hdr->addr1) &&
lq_sta->active_rate_basic)
@@ -714,9 +713,9 @@ static u16 rs_get_adjacent_rate(struct iwl_priv *priv, u8 index, u16 rate_mask,
return (high << 8) | low;
}
-static u32 rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta,
- struct iwl4965_scale_tbl_info *tbl, u8 scale_index,
- u8 ht_possible)
+static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl,
+ u8 scale_index, u8 ht_possible)
{
s32 low;
u16 rate_mask;
@@ -780,7 +779,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
int status;
u8 retries;
int rs_index, index = 0;
- struct iwl4965_lq_sta *lq_sta;
+ struct iwl_lq_sta *lq_sta;
struct iwl_link_quality_cmd *table;
struct sta_info *sta;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
@@ -788,11 +787,11 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hw *hw = local_to_hw(local);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct iwl4965_rate_scale_data *window = NULL;
- struct iwl4965_rate_scale_data *search_win = NULL;
+ struct iwl_rate_scale_data *window = NULL;
+ struct iwl_rate_scale_data *search_win = NULL;
u32 tx_rate;
- struct iwl4965_scale_tbl_info tbl_type;
- struct iwl4965_scale_tbl_info *curr_tbl, *search_tbl;
+ struct iwl_scale_tbl_info tbl_type;
+ struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
u8 active_index = 0;
__le16 fc = hdr->frame_control;
s32 tpt = 0;
@@ -820,7 +819,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
goto out;
- lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
+ lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
!lq_sta->ibss_sta_added)
@@ -831,10 +830,8 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev,
curr_tbl = &(lq_sta->lq_info[active_index]);
search_tbl = &(lq_sta->lq_info[(1 - active_index)]);
- window = (struct iwl4965_rate_scale_data *)
- &(curr_tbl->win[0]);
- search_win = (struct iwl4965_rate_scale_data *)
- &(search_tbl->win[0]);
+ window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]);
+ search_win = (struct iwl_rate_scale_data *)&(search_tbl->win[0]);
/*
* Ignore this Tx frame response if its initial rate doesn't match
@@ -983,7 +980,7 @@ out:
* searching for a new mode.
*/
static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
- struct iwl4965_lq_sta *lq_sta)
+ struct iwl_lq_sta *lq_sta)
{
IWL_DEBUG_RATE("we are staying in the same table\n");
lq_sta->stay_in_tbl = 1; /* only place this gets set */
@@ -1004,8 +1001,8 @@ static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
/*
* Find correct throughput table for given mode of modulation
*/
-static void rs_set_expected_tpt_table(struct iwl4965_lq_sta *lq_sta,
- struct iwl4965_scale_tbl_info *tbl)
+static void rs_set_expected_tpt_table(struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl)
{
if (is_legacy(tbl->lq_type)) {
if (!is_a_band(tbl->lq_type))
@@ -1050,12 +1047,12 @@ static void rs_set_expected_tpt_table(struct iwl4965_lq_sta *lq_sta,
* bit rate will typically need to increase, but not if performance was bad.
*/
static s32 rs_get_best_rate(struct iwl_priv *priv,
- struct iwl4965_lq_sta *lq_sta,
- struct iwl4965_scale_tbl_info *tbl, /* "search" */
+ struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl, /* "search" */
u16 rate_mask, s8 index)
{
/* "active" values */
- struct iwl4965_scale_tbl_info *active_tbl =
+ struct iwl_scale_tbl_info *active_tbl =
&(lq_sta->lq_info[lq_sta->active_tbl]);
s32 active_sr = active_tbl->win[index].success_ratio;
s32 active_tpt = active_tbl->expected_tpt[index];
@@ -1143,10 +1140,10 @@ static s32 rs_get_best_rate(struct iwl_priv *priv,
* Set up search table for MIMO
*/
static int rs_switch_to_mimo2(struct iwl_priv *priv,
- struct iwl4965_lq_sta *lq_sta,
+ struct iwl_lq_sta *lq_sta,
struct ieee80211_conf *conf,
struct sta_info *sta,
- struct iwl4965_scale_tbl_info *tbl, int index)
+ struct iwl_scale_tbl_info *tbl, int index)
{
u16 rate_mask;
s32 rate;
@@ -1156,7 +1153,8 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
!sta->ht_info.ht_supported)
return -1;
- if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
+ if (((sta->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS) >> 2)
+ == IWL_MIMO_PS_STATIC)
return -1;
/* Need both Tx chains/antennas to support MIMO */
@@ -1210,10 +1208,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
* Set up search table for SISO
*/
static int rs_switch_to_siso(struct iwl_priv *priv,
- struct iwl4965_lq_sta *lq_sta,
+ struct iwl_lq_sta *lq_sta,
struct ieee80211_conf *conf,
struct sta_info *sta,
- struct iwl4965_scale_tbl_info *tbl, int index)
+ struct iwl_scale_tbl_info *tbl, int index)
{
u16 rate_mask;
u8 is_green = lq_sta->is_green;
@@ -1270,18 +1268,17 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
* Try to switch to new modulation mode from legacy
*/
static int rs_move_legacy_other(struct iwl_priv *priv,
- struct iwl4965_lq_sta *lq_sta,
+ struct iwl_lq_sta *lq_sta,
struct ieee80211_conf *conf,
struct sta_info *sta,
int index)
{
- struct iwl4965_scale_tbl_info *tbl =
- &(lq_sta->lq_info[lq_sta->active_tbl]);
- struct iwl4965_scale_tbl_info *search_tbl =
- &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
- struct iwl4965_rate_scale_data *window = &(tbl->win[index]);
- u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
- (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
+ struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action = tbl->action;
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
int ret = 0;
@@ -1360,19 +1357,17 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
* Try to switch to new modulation mode from SISO
*/
static int rs_move_siso_to_other(struct iwl_priv *priv,
- struct iwl4965_lq_sta *lq_sta,
+ struct iwl_lq_sta *lq_sta,
struct ieee80211_conf *conf,
- struct sta_info *sta,
- int index)
+ struct sta_info *sta, int index)
{
u8 is_green = lq_sta->is_green;
- struct iwl4965_scale_tbl_info *tbl =
- &(lq_sta->lq_info[lq_sta->active_tbl]);
- struct iwl4965_scale_tbl_info *search_tbl =
- &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
- struct iwl4965_rate_scale_data *window = &(tbl->win[index]);
- u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
- (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
+ struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action = tbl->action;
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
int ret;
@@ -1455,18 +1450,16 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
* Try to switch to new modulation mode from MIMO
*/
static int rs_move_mimo_to_other(struct iwl_priv *priv,
- struct iwl4965_lq_sta *lq_sta,
+ struct iwl_lq_sta *lq_sta,
struct ieee80211_conf *conf,
- struct sta_info *sta,
- int index)
+ struct sta_info *sta, int index)
{
s8 is_green = lq_sta->is_green;
- struct iwl4965_scale_tbl_info *tbl =
- &(lq_sta->lq_info[lq_sta->active_tbl]);
- struct iwl4965_scale_tbl_info *search_tbl =
- &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
- u32 sz = (sizeof(struct iwl4965_scale_tbl_info) -
- (sizeof(struct iwl4965_rate_scale_data) * IWL_RATE_COUNT));
+ struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]);
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action = tbl->action;
/*u8 valid_tx_ant = priv->hw_params.valid_tx_ant;*/
int ret;
@@ -1552,9 +1545,9 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv,
* 2) # times calling this function
* 3) elapsed time in this mode (not used, for now)
*/
-static void rs_stay_in_table(struct iwl4965_lq_sta *lq_sta)
+static void rs_stay_in_table(struct iwl_lq_sta *lq_sta)
{
- struct iwl4965_scale_tbl_info *tbl;
+ struct iwl_scale_tbl_info *tbl;
int i;
int active_tbl;
int flush_interval_passed = 0;
@@ -1642,7 +1635,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
int high = IWL_RATE_INVALID;
int index;
int i;
- struct iwl4965_rate_scale_data *window = NULL;
+ struct iwl_rate_scale_data *window = NULL;
int current_tpt = IWL_INVALID_VALUE;
int low_tpt = IWL_INVALID_VALUE;
int high_tpt = IWL_INVALID_VALUE;
@@ -1651,8 +1644,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
__le16 fc;
u16 rate_mask;
u8 update_lq = 0;
- struct iwl4965_lq_sta *lq_sta;
- struct iwl4965_scale_tbl_info *tbl, *tbl1;
+ struct iwl_lq_sta *lq_sta;
+ struct iwl_scale_tbl_info *tbl, *tbl1;
u16 rate_scale_index_msk = 0;
u32 rate;
u8 is_green = 0;
@@ -1675,7 +1668,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
if (!sta || !sta->rate_ctrl_priv)
return;
- lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
+ lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
tid = rs_tl_add_packet(lq_sta, hdr);
@@ -2030,8 +2023,8 @@ static void rs_initialize_lq(struct iwl_priv *priv,
struct ieee80211_conf *conf,
struct sta_info *sta)
{
- struct iwl4965_lq_sta *lq_sta;
- struct iwl4965_scale_tbl_info *tbl;
+ struct iwl_lq_sta *lq_sta;
+ struct iwl_scale_tbl_info *tbl;
int rate_idx;
int i;
u32 rate;
@@ -2042,7 +2035,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
if (!sta || !sta->rate_ctrl_priv)
goto out;
- lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
+ lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
i = sta->last_txrate_idx;
if ((lq_sta->lq.sta_id == 0xff) &&
@@ -2096,7 +2089,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
struct sta_info *sta;
__le16 fc;
struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
- struct iwl4965_lq_sta *lq_sta;
+ struct iwl_lq_sta *lq_sta;
IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
@@ -2113,7 +2106,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev,
goto out;
}
- lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv;
+ lq_sta = (struct iwl_lq_sta *)sta->rate_ctrl_priv;
i = sta->last_txrate_idx;
if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
@@ -2149,14 +2142,14 @@ out:
static void *rs_alloc_sta(void *priv_rate, gfp_t gfp)
{
- struct iwl4965_lq_sta *lq_sta;
+ struct iwl_lq_sta *lq_sta;
struct iwl_priv *priv;
int i, j;
priv = (struct iwl_priv *)priv_rate;
IWL_DEBUG_RATE("create station rate scale window\n");
- lq_sta = kzalloc(sizeof(struct iwl4965_lq_sta), gfp);
+ lq_sta = kzalloc(sizeof(struct iwl_lq_sta), gfp);
if (lq_sta == NULL)
return NULL;
@@ -2165,7 +2158,7 @@ static void *rs_alloc_sta(void *priv_rate, gfp_t gfp)
for (j = 0; j < LQ_SIZE; j++)
for (i = 0; i < IWL_RATE_COUNT; i++)
- rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i]));
+ rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
return lq_sta;
}
@@ -2178,7 +2171,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
struct ieee80211_conf *conf = &local->hw.conf;
struct ieee80211_supported_band *sband;
struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
- struct iwl4965_lq_sta *lq_sta = priv_sta;
+ struct iwl_lq_sta *lq_sta = priv_sta;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
@@ -2187,7 +2180,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
sta->txrate_idx = 3;
for (j = 0; j < LQ_SIZE; j++)
for (i = 0; i < IWL_RATE_COUNT; i++)
- rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i]));
+ rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
IWL_DEBUG_RATE("LQ: *** rate scale global init ***\n");
/* TODO: what is a good starting rate for STA? About middle? Maybe not
@@ -2271,10 +2264,9 @@ static void rs_rate_init(void *priv_rate, void *priv_sta,
}
static void rs_fill_link_cmd(const struct iwl_priv *priv,
- struct iwl4965_lq_sta *lq_sta,
- u32 new_rate)
+ struct iwl_lq_sta *lq_sta, u32 new_rate)
{
- struct iwl4965_scale_tbl_info tbl_type;
+ struct iwl_scale_tbl_info tbl_type;
int index = 0;
int rate_idx;
int repeat_rate = 0;
@@ -2402,6 +2394,7 @@ static void rs_free(void *priv_rate)
static void rs_clear(void *priv_rate)
{
+#ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_priv *priv = (struct iwl_priv *) priv_rate;
IWL_DEBUG_RATE("enter\n");
@@ -2409,11 +2402,12 @@ static void rs_clear(void *priv_rate)
/* TODO - add rate scale state reset */
IWL_DEBUG_RATE("leave\n");
+#endif /* CONFIG_IWLWIFI_DEBUG */
}
static void rs_free_sta(void *priv_rate, void *priv_sta)
{
- struct iwl4965_lq_sta *lq_sta = priv_sta;
+ struct iwl_lq_sta *lq_sta = priv_sta;
struct iwl_priv *priv;
priv = (struct iwl_priv *)priv_rate;
@@ -2429,8 +2423,8 @@ static int open_file_generic(struct inode *inode, struct file *file)
file->private_data = inode->i_private;
return 0;
}
-static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
- u32 *rate_n_flags, int index)
+static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
+ u32 *rate_n_flags, int index)
{
struct iwl_priv *priv;
@@ -2453,7 +2447,7 @@ static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta,
static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
- struct iwl4965_lq_sta *lq_sta = file->private_data;
+ struct iwl_lq_sta *lq_sta = file->private_data;
struct iwl_priv *priv;
char buf[64];
int buf_size;
@@ -2493,7 +2487,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
int desc = 0;
int i = 0;
- struct iwl4965_lq_sta *lq_sta = file->private_data;
+ struct iwl_lq_sta *lq_sta = file->private_data;
desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
@@ -2541,7 +2535,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
int desc = 0;
int i, j;
- struct iwl4965_lq_sta *lq_sta = file->private_data;
+ struct iwl_lq_sta *lq_sta = file->private_data;
for (i = 0; i < LQ_SIZE; i++) {
desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
"rate=0x%X\n",
@@ -2570,7 +2564,7 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
static void rs_add_debugfs(void *priv, void *priv_sta,
struct dentry *dir)
{
- struct iwl4965_lq_sta *lq_sta = priv_sta;
+ struct iwl_lq_sta *lq_sta = priv_sta;
lq_sta->rs_sta_dbgfs_scale_table_file =
debugfs_create_file("rate_scale_table", 0600, dir,
lq_sta, &rs_sta_dbgfs_scale_table_ops);
@@ -2585,7 +2579,7 @@ static void rs_add_debugfs(void *priv, void *priv_sta,
static void rs_remove_debugfs(void *priv, void *priv_sta)
{
- struct iwl4965_lq_sta *lq_sta = priv_sta;
+ struct iwl_lq_sta *lq_sta = priv_sta;
debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
@@ -2609,104 +2603,12 @@ static struct rate_control_ops rs_ops = {
#endif
};
-int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
-{
- struct ieee80211_local *local = hw_to_local(hw);
- struct iwl_priv *priv = hw->priv;
- struct iwl4965_lq_sta *lq_sta;
- struct sta_info *sta;
- int cnt = 0, i;
- u32 samples = 0, success = 0, good = 0;
- unsigned long now = jiffies;
- u32 max_time = 0;
- u8 lq_type, antenna;
-
- rcu_read_lock();
-
- sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
- if (!sta || !sta->rate_ctrl_priv) {
- if (sta)
- IWL_DEBUG_RATE("leave - no private rate data!\n");
- else
- IWL_DEBUG_RATE("leave - no station!\n");
- rcu_read_unlock();
- return sprintf(buf, "station %d not found\n", sta_id);
- }
-
- lq_sta = (void *)sta->rate_ctrl_priv;
-
- lq_type = lq_sta->lq_info[lq_sta->active_tbl].lq_type;
- antenna = lq_sta->lq_info[lq_sta->active_tbl].ant_type;
-
- if (is_legacy(lq_type))
- i = IWL_RATE_54M_INDEX;
- else
- i = IWL_RATE_60M_INDEX;
- while (1) {
- u64 mask;
- int j;
- int active = lq_sta->active_tbl;
-
- cnt +=
- sprintf(&buf[cnt], " %2dMbs: ", iwl_rates[i].ieee / 2);
-
- mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
- for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
- buf[cnt++] =
- (lq_sta->lq_info[active].win[i].data & mask)
- ? '1' : '0';
-
- samples += lq_sta->lq_info[active].win[i].counter;
- good += lq_sta->lq_info[active].win[i].success_counter;
- success += lq_sta->lq_info[active].win[i].success_counter *
- iwl_rates[i].ieee;
-
- if (lq_sta->lq_info[active].win[i].stamp) {
- int delta =
- jiffies_to_msecs(now -
- lq_sta->lq_info[active].win[i].stamp);
-
- if (delta > max_time)
- max_time = delta;
-
- cnt += sprintf(&buf[cnt], "%5dms\n", delta);
- } else
- buf[cnt++] = '\n';
-
- j = iwl4965_get_prev_ieee_rate(i);
- if (j == i)
- break;
- i = j;
- }
-
- /*
- * Display the average rate of all samples taken.
- * NOTE: We multiply # of samples by 2 since the IEEE measurement
- * added from iwl_rates is actually 2X the rate.
- */
- if (samples)
- cnt += sprintf(&buf[cnt],
- "\nAverage rate is %3d.%02dMbs over last %4dms\n"
- "%3d%% success (%d good packets over %d tries)\n",
- success / (2 * samples), (success * 5 / samples) % 10,
- max_time, good * 100 / samples, good, samples);
- else
- cnt += sprintf(&buf[cnt], "\nAverage rate: 0Mbs\n");
-
- cnt += sprintf(&buf[cnt], "\nrate scale type %d antenna %d "
- "active_search %d rate index %d\n", lq_type, antenna,
- lq_sta->search_better_tbl, sta->last_txrate_idx);
-
- rcu_read_unlock();
- return cnt;
-}
-
-int iwl4965_rate_control_register(void)
+int iwlagn_rate_control_register(void)
{
return ieee80211_rate_control_register(&rs_ops);
}
-void iwl4965_rate_control_unregister(void)
+void iwlagn_rate_control_unregister(void)
{
ieee80211_rate_control_unregister(&rs_ops);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index 9b9972885aa..84d4d1e3375 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -24,8 +24,8 @@
*
*****************************************************************************/
-#ifndef __iwl_4965_rs_h__
-#define __iwl_4965_rs_h__
+#ifndef __iwl_agn_rs_h__
+#define __iwl_agn_rs_h__
#include "iwl-dev.h"
@@ -88,7 +88,7 @@ enum {
#define IWL_RATE_5M_MASK (1 << IWL_RATE_5M_INDEX)
#define IWL_RATE_11M_MASK (1 << IWL_RATE_11M_INDEX)
-/* 4965 uCode API values for legacy bit rates, both OFDM and CCK */
+/* uCode API values for legacy bit rates, both OFDM and CCK */
enum {
IWL_RATE_6M_PLCP = 13,
IWL_RATE_9M_PLCP = 15,
@@ -107,7 +107,7 @@ enum {
/*FIXME:RS:add IWL_RATE_LEGACY_INVM_PLCP = 0,*/
};
-/* 4965 uCode API values for OFDM high-throughput (HT) bit rates */
+/* uCode API values for OFDM high-throughput (HT) bit rates */
enum {
IWL_RATE_SISO_6M_PLCP = 0,
IWL_RATE_SISO_12M_PLCP = 1,
@@ -287,15 +287,6 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index)
}
/**
- * iwl4965_fill_rs_info - Fill an output text buffer with the rate representation
- *
- * NOTE: This is provided as a quick mechanism for a user to visualize
- * the performance of the rate control algorithm and is not meant to be
- * parsed software.
- */
-extern int iwl4965_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
-
-/**
* iwl4965_rate_control_register - Register the rate control algorithm callbacks
*
* Since the rate control algorithm is hardware specific, there is no need
@@ -305,7 +296,7 @@ extern int iwl4965_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
* ieee80211_register_hw
*
*/
-extern int iwl4965_rate_control_register(void);
+extern int iwlagn_rate_control_register(void);
/**
* iwl4965_rate_control_unregister - Unregister the rate control callbacks
@@ -313,6 +304,6 @@ extern int iwl4965_rate_control_register(void);
* This should be called after calling ieee80211_unregister_hw, but before
* the driver is unloaded.
*/
-extern void iwl4965_rate_control_unregister(void);
+extern void iwlagn_rate_control_unregister(void);
-#endif
+#endif /* __iwl_agn__rs__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 71f5da3fe5c..e01f048a02d 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -29,7 +29,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
@@ -65,7 +64,7 @@
* NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk
*/
-#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link 4965AGN driver for Linux"
+#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux"
#ifdef CONFIG_IWLWIFI_DEBUG
#define VD "d"
@@ -73,7 +72,7 @@
#define VD
#endif
-#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
#define VS "s"
#else
#define VS
@@ -86,6 +85,7 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("iwl4965");
/*************** STATION TABLE MANAGEMENT ****
* mac80211 should be examined to determine if sta_info is duplicating
@@ -181,14 +181,14 @@ static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
}
/**
- * iwl4965_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
+ * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed
* @priv: staging_rxon is compared to active_rxon
*
* If the RXON structure is changing enough to require a new tune,
* or is clearing the RXON_FILTER_ASSOC_MSK, then return 1 to indicate that
* a new tune (full RXON command, rather than RXON_ASSOC cmd) is required.
*/
-static int iwl4965_full_rxon_required(struct iwl_priv *priv)
+static int iwl_full_rxon_required(struct iwl_priv *priv)
{
/* These items are only settable from the full RXON command */
@@ -207,7 +207,6 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv)
priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
(priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
- (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) ||
(priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
return 1;
@@ -263,7 +262,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
/* If we don't need to send a full RXON, we can use
* iwl4965_rxon_assoc_cmd which is used to reconfigure filter
* and other flags for the current radio configuration. */
- if (!iwl4965_full_rxon_required(priv)) {
+ if (!iwl_full_rxon_required(priv)) {
ret = iwl_send_rxon_assoc(priv);
if (ret) {
IWL_ERROR("Error setting RXON_ASSOC (%d)\n", ret);
@@ -444,11 +443,10 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
list_add(&frame->list, &priv->free_frames);
}
-unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
- struct ieee80211_hdr *hdr,
- const u8 *dest, int left)
+static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+ struct ieee80211_hdr *hdr,
+ const u8 *dest, int left)
{
-
if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
(priv->iw_mode != IEEE80211_IF_TYPE_AP)))
@@ -487,6 +485,38 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv)
return IWL_RATE_6M_PLCP;
}
+unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv,
+ struct iwl_frame *frame, u8 rate)
+{
+ struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+ unsigned int frame_size;
+
+ tx_beacon_cmd = &frame->u.beacon;
+ memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
+
+ tx_beacon_cmd->tx.sta_id = priv->hw_params.bcast_sta_id;
+ tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+ frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
+ iwl_bcast_addr,
+ sizeof(frame->u) - sizeof(*tx_beacon_cmd));
+
+ BUG_ON(frame_size > MAX_MPDU_SIZE);
+ tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+
+ if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
+ tx_beacon_cmd->tx.rate_n_flags =
+ iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
+ else
+ tx_beacon_cmd->tx.rate_n_flags =
+ iwl_hw_set_rate_n_flags(rate, 0);
+
+ tx_beacon_cmd->tx.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK |
+ TX_CMD_FLG_TSF_MSK |
+ TX_CMD_FLG_STA_RATE_MSK;
+
+ return sizeof(*tx_beacon_cmd) + frame_size;
+}
static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
{
struct iwl_frame *frame;
@@ -556,8 +586,6 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
iwl_conf->supported_chan_width = 0;
}
- iwl_conf->tx_mimo_ps_mode =
- (u8)((ht_conf->cap & IEEE80211_HT_CAP_MIMO_PS) >> 2);
memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16);
iwl_conf->control_channel = ht_bss_conf->primary_channel;
@@ -608,7 +636,6 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
}
#define MAX_UCODE_BEACON_INTERVAL 4096
-#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA)
static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val)
{
@@ -638,7 +665,7 @@ static void iwl4965_setup_rxon_timing(struct iwl_priv *priv)
priv->rxon_timing.timestamp.dw[0] =
cpu_to_le32(priv->timestamp & 0xFFFFFFFF);
- priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
+ priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
tsf = priv->timestamp;
@@ -853,7 +880,7 @@ static void iwl4965_set_rate(struct iwl_priv *priv)
(IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
}
-#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
#include "iwl-spectrum.h"
@@ -1057,7 +1084,7 @@ static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
-#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif);
@@ -1231,6 +1258,37 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
wake_up_interruptible(&priv->wait_command_queue);
}
+int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ret = iwl_grab_nic_access(priv);
+ if (ret)
+ goto err;
+
+ if (src == IWL_PWR_SRC_VAUX) {
+ u32 val;
+ ret = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
+ &val);
+
+ if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)
+ iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+ } else {
+ iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+ }
+
+ iwl_release_nic_access(priv);
+err:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return ret;
+}
+
/**
* iwl4965_setup_rx_handlers - Initialize Rx handler callbacks
*
@@ -2129,7 +2187,10 @@ static void __iwl4965_down(struct iwl_priv *priv)
udelay(5);
/* FIXME: apm_ops.suspend(priv) */
- priv->cfg->ops->lib->apm_ops.reset(priv);
+ if (exit_pending || test_bit(STATUS_IN_SUSPEND, &priv->status))
+ priv->cfg->ops->lib->apm_ops.stop(priv);
+ else
+ priv->cfg->ops->lib->apm_ops.reset(priv);
priv->cfg->ops->lib->free_shared_mem(priv);
exit:
@@ -2170,17 +2231,16 @@ static int __iwl4965_up(struct iwl_priv *priv)
}
/* If platform's RF_KILL switch is NOT set to KILL */
- if (iwl_read32(priv, CSR_GP_CNTRL) &
- CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+ if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
clear_bit(STATUS_RF_KILL_HW, &priv->status);
else
set_bit(STATUS_RF_KILL_HW, &priv->status);
- if (!test_bit(STATUS_IN_SUSPEND, &priv->status) &&
- iwl_is_rfkill(priv)) {
+ if (iwl_is_rfkill(priv)) {
+ iwl4965_enable_interrupts(priv);
IWL_WARNING("Radio disabled by %s RF Kill switch\n",
test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW");
- return -ENODEV;
+ return 0;
}
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
@@ -2216,11 +2276,6 @@ static int __iwl4965_up(struct iwl_priv *priv)
memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
priv->ucode_data.len);
- /* We return success when we resume from suspend and rf_kill is on. */
- if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
- test_bit(STATUS_RF_KILL_SW, &priv->status))
- return 0;
-
for (i = 0; i < MAX_HW_RESTARTS; i++) {
iwl_clear_stations_table(priv);
@@ -2415,7 +2470,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
unsigned long flags;
if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
- IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
+ IWL_ERROR("%s Should not be called in AP mode\n", __func__);
return;
}
@@ -2491,7 +2546,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv)
default:
IWL_ERROR("%s Should not be called in %d mode\n",
- __FUNCTION__, priv->iw_mode);
+ __func__, priv->iw_mode);
break;
}
@@ -2547,6 +2602,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
int ret;
+ u16 pci_cmd;
IWL_DEBUG_MAC80211("enter\n");
@@ -2557,6 +2613,13 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
pci_restore_state(priv->pci_dev);
pci_enable_msi(priv->pci_dev);
+ /* enable interrupts if needed: hw bug w/a */
+ pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd);
+ if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
+ pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
+ }
+
ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED,
DRV_NAME, priv);
if (ret) {
@@ -2589,6 +2652,9 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
if (ret)
goto out_release_irq;
+ if (iwl_is_rfkill(priv))
+ goto out;
+
IWL_DEBUG_INFO("Start UP work done.\n");
if (test_bit(STATUS_IN_SUSPEND, &priv->status))
@@ -2608,6 +2674,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw)
}
}
+out:
priv->is_open = 1;
IWL_DEBUG_MAC80211("leave\n");
return 0;
@@ -2659,7 +2726,7 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct iwl_priv *priv = hw->priv;
- IWL_DEBUG_MAC80211("enter\n");
+ IWL_DEBUG_MACDUMP("enter\n");
if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
IWL_DEBUG_MAC80211("leave - monitor\n");
@@ -2673,7 +2740,7 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (iwl_tx_skb(priv, skb))
dev_kfree_skb_any(skb);
- IWL_DEBUG_MAC80211("leave\n");
+ IWL_DEBUG_MACDUMP("leave\n");
return 0;
}
@@ -2773,6 +2840,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
spin_lock_irqsave(&priv->lock, flags);
+
/* if we are switching from ht to 2.4 clear flags
* from any ht related info since 2.4 does not
* support ht */
@@ -3102,6 +3170,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
if (bss_conf->assoc) {
priv->assoc_id = bss_conf->aid;
priv->beacon_int = bss_conf->beacon_int;
+ priv->power_data.dtim_period = bss_conf->dtim_period;
priv->timestamp = bss_conf->timestamp;
priv->assoc_capability = bss_conf->assoc_capability;
priv->next_scan_jiffies = jiffies +
@@ -3345,6 +3414,39 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
return 0;
}
+static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
+ enum ieee80211_ampdu_mlme_action action,
+ const u8 *addr, u16 tid, u16 *ssn)
+{
+ struct iwl_priv *priv = hw->priv;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n",
+ print_mac(mac, addr), tid);
+
+ if (!(priv->cfg->sku & IWL_SKU_N))
+ return -EACCES;
+
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ IWL_DEBUG_HT("start Rx\n");
+ return iwl_rx_agg_start(priv, addr, tid, *ssn);
+ case IEEE80211_AMPDU_RX_STOP:
+ IWL_DEBUG_HT("stop Rx\n");
+ return iwl_rx_agg_stop(priv, addr, tid);
+ case IEEE80211_AMPDU_TX_START:
+ IWL_DEBUG_HT("start Tx\n");
+ return iwl_tx_agg_start(priv, addr, tid, ssn);
+ case IEEE80211_AMPDU_TX_STOP:
+ IWL_DEBUG_HT("stop Tx\n");
+ return iwl_tx_agg_stop(priv, addr, tid);
+ default:
+ IWL_DEBUG_HT("unknown\n");
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw,
struct ieee80211_tx_queue_stats *stats)
{
@@ -3486,7 +3588,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
priv->assoc_id = 0;
timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
- priv->timestamp = le64_to_cpu(timestamp) + (priv->beacon_int * 1000);
+ priv->timestamp = le64_to_cpu(timestamp);
IWL_DEBUG_MAC80211("leave\n");
spin_unlock_irqrestore(&priv->lock, flags);
@@ -3592,15 +3694,6 @@ static ssize_t show_temperature(struct device *d,
static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
-static ssize_t show_rs_window(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct iwl_priv *priv = d->driver_data;
- return iwl4965_fill_rs_info(priv->hw, buf, IWL_AP_ID);
-}
-static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
-
static ssize_t show_tx_power(struct device *d,
struct device_attribute *attr, char *buf)
{
@@ -3699,7 +3792,7 @@ static ssize_t store_filter_flags(struct device *d,
static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
store_filter_flags);
-#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
static ssize_t show_measurement(struct device *d,
struct device_attribute *attr, char *buf)
@@ -3707,7 +3800,7 @@ static ssize_t show_measurement(struct device *d,
struct iwl_priv *priv = dev_get_drvdata(d);
struct iwl4965_spectrum_notification measure_report;
u32 size = sizeof(measure_report), len = 0, ofs = 0;
- u8 *data = (u8 *) & measure_report;
+ u8 *data = (u8 *)&measure_report;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
@@ -3770,7 +3863,7 @@ static ssize_t store_measurement(struct device *d,
static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
show_measurement, store_measurement);
-#endif /* CONFIG_IWL4965_SPECTRUM_MEASUREMENT */
+#endif /* CONFIG_IWLAGN_SPECTRUM_MEASUREMENT */
static ssize_t store_retry_rate(struct device *d,
struct device_attribute *attr,
@@ -3800,77 +3893,54 @@ static ssize_t store_power_level(struct device *d,
const char *buf, size_t count)
{
struct iwl_priv *priv = dev_get_drvdata(d);
- int rc;
+ int ret;
int mode;
mode = simple_strtoul(buf, NULL, 0);
mutex_lock(&priv->mutex);
if (!iwl_is_ready(priv)) {
- rc = -EAGAIN;
+ ret = -EAGAIN;
goto out;
}
- rc = iwl_power_set_user_mode(priv, mode);
- if (rc) {
+ ret = iwl_power_set_user_mode(priv, mode);
+ if (ret) {
IWL_DEBUG_MAC80211("failed setting power mode.\n");
goto out;
}
- rc = count;
+ ret = count;
out:
mutex_unlock(&priv->mutex);
- return rc;
+ return ret;
}
-#define MAX_WX_STRING 80
-
-/* Values are in microsecond */
-static const s32 timeout_duration[] = {
- 350000,
- 250000,
- 75000,
- 37000,
- 25000,
-};
-static const s32 period_duration[] = {
- 400000,
- 700000,
- 1000000,
- 1000000,
- 1000000
-};
-
static ssize_t show_power_level(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwl_priv *priv = dev_get_drvdata(d);
+ int mode = priv->power_data.user_power_setting;
+ int system = priv->power_data.system_power_setting;
int level = priv->power_data.power_mode;
char *p = buf;
- p += sprintf(p, "%d ", level);
- switch (level) {
- case IWL_POWER_MODE_CAM:
- case IWL_POWER_AC:
- p += sprintf(p, "(AC)");
+ switch (system) {
+ case IWL_POWER_SYS_AUTO:
+ p += sprintf(p, "SYSTEM:auto");
break;
- case IWL_POWER_BATTERY:
- p += sprintf(p, "(BATTERY)");
+ case IWL_POWER_SYS_AC:
+ p += sprintf(p, "SYSTEM:ac");
+ break;
+ case IWL_POWER_SYS_BATTERY:
+ p += sprintf(p, "SYSTEM:battery");
break;
- default:
- p += sprintf(p,
- "(Timeout %dms, Period %dms)",
- timeout_duration[level - 1] / 1000,
- period_duration[level - 1] / 1000);
}
-/*
- if (!(priv->power_mode & IWL_POWER_ENABLED))
- p += sprintf(p, " OFF\n");
- else
- p += sprintf(p, " \n");
-*/
- p += sprintf(p, " \n");
- return (p - buf + 1);
+
+ p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto");
+ p += sprintf(p, "\tINDEX:%d", level);
+ p += sprintf(p, "\n");
+ return p - buf + 1;
}
static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
@@ -3945,7 +4015,7 @@ static ssize_t show_statistics(struct device *d,
struct iwl_priv *priv = dev_get_drvdata(d);
u32 size = sizeof(struct iwl_notif_statistics);
u32 len = 0, ofs = 0;
- u8 *data = (u8 *) & priv->statistics;
+ u8 *data = (u8 *)&priv->statistics;
int rc = 0;
if (!iwl_is_alive(priv))
@@ -4041,12 +4111,11 @@ static struct attribute *iwl4965_sysfs_entries[] = {
&dev_attr_channels.attr,
&dev_attr_flags.attr,
&dev_attr_filter_flags.attr,
-#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
&dev_attr_measurement.attr,
#endif
&dev_attr_power_level.attr,
&dev_attr_retry_rate.attr,
- &dev_attr_rs_window.attr,
&dev_attr_statistics.attr,
&dev_attr_status.attr,
&dev_attr_temperature.attr,
@@ -4303,15 +4372,18 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
iwl_dbgfs_unregister(priv);
sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
+ /* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to
+ * to be called and iwl4965_down since we are removing the device
+ * we need to set STATUS_EXIT_PENDING bit.
+ */
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
if (priv->mac80211_registered) {
ieee80211_unregister_hw(priv->hw);
priv->mac80211_registered = 0;
+ } else {
+ iwl4965_down(priv);
}
- set_bit(STATUS_EXIT_PENDING, &priv->status);
-
- iwl4965_down(priv);
-
/* make sure we flush any pending irq or
* tasklet for the driver
*/
@@ -4394,8 +4466,10 @@ static int iwl4965_pci_resume(struct pci_dev *pdev)
/* Hardware specific file defines the PCI IDs table for that hardware module */
static struct pci_device_id iwl_hw_card_ids[] = {
+#ifdef CONFIG_IWL4965
{IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
{IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
+#endif /* CONFIG_IWL4965 */
#ifdef CONFIG_IWL5000
{IWL_PCI_DEVICE(0x4232, 0x1205, iwl5100_bg_cfg)},
{IWL_PCI_DEVICE(0x4232, 0x1305, iwl5100_bg_cfg)},
@@ -4431,7 +4505,7 @@ static int __init iwl4965_init(void)
printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
- ret = iwl4965_rate_control_register();
+ ret = iwlagn_rate_control_register();
if (ret) {
IWL_ERROR("Unable to register rate control algorithm: %d\n", ret);
return ret;
@@ -4446,14 +4520,14 @@ static int __init iwl4965_init(void)
return ret;
error_register:
- iwl4965_rate_control_unregister();
+ iwlagn_rate_control_unregister();
return ret;
}
static void __exit iwl4965_exit(void)
{
pci_unregister_driver(&iwl_driver);
- iwl4965_rate_control_unregister();
+ iwlagn_rate_control_unregister();
}
module_exit(iwl4965_exit);
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index e9bb1de0ce3..28b5b09996e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -666,8 +666,7 @@ struct iwl4965_rxon_assoc_cmd {
__le16 reserved;
} __attribute__ ((packed));
-
-
+#define IWL_CONN_MAX_LISTEN_INTERVAL 10
/*
* REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
@@ -1076,10 +1075,12 @@ struct iwl4965_rx_frame {
} __attribute__ ((packed));
/* Fixed (non-configurable) rx data from phy */
-#define RX_PHY_FLAGS_ANTENNAE_OFFSET (4)
-#define RX_PHY_FLAGS_ANTENNAE_MASK (0x70)
-#define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */
-#define IWL_AGC_DB_POS (7)
+
+#define IWL49_RX_RES_PHY_CNT 14
+#define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET (4)
+#define IWL49_RX_PHY_FLAGS_ANTENNAE_MASK (0x70)
+#define IWL49_AGC_DB_MASK (0x3f80) /* MASK(7,13) */
+#define IWL49_AGC_DB_POS (7)
struct iwl4965_rx_non_cfg_phy {
__le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */
__le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */
@@ -1087,12 +1088,30 @@ struct iwl4965_rx_non_cfg_phy {
u8 pad[0];
} __attribute__ ((packed));
+
+#define IWL50_RX_RES_PHY_CNT 8
+#define IWL50_RX_RES_AGC_IDX 1
+#define IWL50_RX_RES_RSSI_AB_IDX 2
+#define IWL50_RX_RES_RSSI_C_IDX 3
+#define IWL50_OFDM_AGC_MSK 0xfe00
+#define IWL50_OFDM_AGC_BIT_POS 9
+#define IWL50_OFDM_RSSI_A_MSK 0x00ff
+#define IWL50_OFDM_RSSI_A_BIT_POS 0
+#define IWL50_OFDM_RSSI_B_MSK 0xff0000
+#define IWL50_OFDM_RSSI_B_BIT_POS 16
+#define IWL50_OFDM_RSSI_C_MSK 0x00ff
+#define IWL50_OFDM_RSSI_C_BIT_POS 0
+
+struct iwl5000_non_cfg_phy {
+ __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* upto 8 phy entries */
+} __attribute__ ((packed));
+
+
/*
* REPLY_RX = 0xc3 (response only, not a command)
* Used only for legacy (non 11n) frames.
*/
-#define RX_RES_PHY_CNT 14
-struct iwl4965_rx_phy_res {
+struct iwl_rx_phy_res {
u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */
u8 cfg_phy_cnt; /* configurable DSP phy data byte count */
u8 stat_id; /* configurable DSP phy data set ID */
@@ -1101,8 +1120,7 @@ struct iwl4965_rx_phy_res {
__le32 beacon_time_stamp; /* beacon at on-air rise */
__le16 phy_flags; /* general phy flags: band, modulation, ... */
__le16 channel; /* channel number */
- __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */
- __le32 reserved2;
+ u8 non_cfg_phy_buf[32]; /* for various implementations of non_cfg_phy */
__le32 rate_n_flags; /* RATE_MCS_* */
__le16 byte_count; /* frame's byte-count */
__le16 reserved3;
@@ -1993,7 +2011,7 @@ struct iwl4965_spectrum_notification {
*****************************************************************************/
/**
- * struct iwl4965_powertable_cmd - Power Table Command
+ * struct iwl_powertable_cmd - Power Table Command
* @flags: See below:
*
* POWER_TABLE_CMD = 0x77 (command, has simple generic response)
@@ -2027,7 +2045,7 @@ struct iwl4965_spectrum_notification {
#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3)
#define IWL_POWER_FAST_PD __constant_cpu_to_le16(1 << 4)
-struct iwl4965_powertable_cmd {
+struct iwl_powertable_cmd {
__le16 flags;
u8 keep_alive_seconds;
u8 debug_flags;
@@ -2324,7 +2342,7 @@ struct iwl4965_beacon_notif {
/*
* REPLY_TX_BEACON = 0x91 (command, has simple generic response)
*/
-struct iwl4965_tx_beacon_cmd {
+struct iwl_tx_beacon_cmd {
struct iwl_tx_cmd tx;
__le16 tim_idx;
u8 tim_size;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index a44188bf445..80f2f84defa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -28,7 +28,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <net/mac80211.h>
struct iwl_priv; /* FIXME: remove */
@@ -383,8 +382,8 @@ void iwl_reset_qos(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_reset_qos);
-#define MAX_BIT_RATE_40_MHZ 0x96; /* 150 Mbps */
-#define MAX_BIT_RATE_20_MHZ 0x48; /* 72 Mbps */
+#define MAX_BIT_RATE_40_MHZ 0x96 /* 150 Mbps */
+#define MAX_BIT_RATE_20_MHZ 0x48 /* 72 Mbps */
static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
struct ieee80211_ht_info *ht_info,
enum ieee80211_band band)
@@ -593,12 +592,11 @@ static void iwlcore_free_geos(struct iwl_priv *priv)
clear_bit(STATUS_GEO_CONFIGURED, &priv->status);
}
-static u8 is_single_rx_stream(struct iwl_priv *priv)
+static bool is_single_rx_stream(struct iwl_priv *priv)
{
return !priv->current_ht_config.is_ht ||
((priv->current_ht_config.supp_mcs_set[1] == 0) &&
- (priv->current_ht_config.supp_mcs_set[2] == 0)) ||
- priv->ps_mode == IWL_MIMO_PS_STATIC;
+ (priv->current_ht_config.supp_mcs_set[2] == 0));
}
static u8 iwl_is_channel_extension(struct iwl_priv *priv,
@@ -705,33 +703,39 @@ EXPORT_SYMBOL(iwl_set_rxon_ht);
* MIMO (dual stream) requires at least 2, but works better with 3.
* This does not determine *which* chains to use, just how many.
*/
-static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
- u8 *idle_state, u8 *rx_state)
+static int iwl_get_active_rx_chain_count(struct iwl_priv *priv)
{
- u8 is_single = is_single_rx_stream(priv);
- u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
+ bool is_single = is_single_rx_stream(priv);
+ bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
/* # of Rx chains to use when expecting MIMO. */
if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
- *rx_state = 2;
+ return 2;
else
- *rx_state = 3;
+ return 3;
+}
+static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
+{
+ int idle_cnt;
+ bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
/* # Rx chains when idling and maybe trying to save power */
switch (priv->ps_mode) {
case IWL_MIMO_PS_STATIC:
case IWL_MIMO_PS_DYNAMIC:
- *idle_state = (is_cam) ? 2 : 1;
+ idle_cnt = (is_cam) ? 2 : 1;
break;
case IWL_MIMO_PS_NONE:
- *idle_state = (is_cam) ? *rx_state : 1;
+ idle_cnt = (is_cam) ? active_cnt : 1;
break;
+ case IWL_MIMO_PS_INVALID:
default:
- *idle_state = 1;
+ IWL_ERROR("invalide mimo ps mode %d\n", priv->ps_mode);
+ WARN_ON(1);
+ idle_cnt = -1;
break;
}
-
- return 0;
+ return idle_cnt;
}
/**
@@ -742,34 +746,44 @@ static int iwlcore_get_rx_chain_counter(struct iwl_priv *priv,
*/
void iwl_set_rxon_chain(struct iwl_priv *priv)
{
- u8 is_single = is_single_rx_stream(priv);
- u8 idle_state, rx_state;
-
- priv->staging_rxon.rx_chain = 0;
- rx_state = idle_state = 3;
+ bool is_single = is_single_rx_stream(priv);
+ bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status);
+ u8 idle_rx_cnt, active_rx_cnt;
+ u16 rx_chain;
/* Tell uCode which antennas are actually connected.
* Before first association, we assume all antennas are connected.
* Just after first association, iwl_chain_noise_calibration()
* checks which antennas actually *are* connected. */
- priv->staging_rxon.rx_chain |=
- cpu_to_le16(priv->hw_params.valid_rx_ant <<
- RXON_RX_CHAIN_VALID_POS);
+ rx_chain = priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
/* How many receivers should we use? */
- iwlcore_get_rx_chain_counter(priv, &idle_state, &rx_state);
- priv->staging_rxon.rx_chain |=
- cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
- priv->staging_rxon.rx_chain |=
- cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS);
-
- if (!is_single && (rx_state >= 2) &&
- !test_bit(STATUS_POWER_PMI, &priv->status))
+ active_rx_cnt = iwl_get_active_rx_chain_count(priv);
+ idle_rx_cnt = iwl_get_idle_rx_chain_count(priv, active_rx_cnt);
+
+ /* correct rx chain count accoridng hw settings */
+ if (priv->hw_params.rx_chains_num < active_rx_cnt)
+ active_rx_cnt = priv->hw_params.rx_chains_num;
+
+ if (priv->hw_params.rx_chains_num < idle_rx_cnt)
+ idle_rx_cnt = priv->hw_params.rx_chains_num;
+
+ rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
+ rx_chain |= idle_rx_cnt << RXON_RX_CHAIN_CNT_POS;
+
+ priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
+
+ if (!is_single && (active_rx_cnt >= 2) && is_cam)
priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
else
priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
- IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
+ IWL_DEBUG_ASSOC("rx_chain=0x%Xi active=%d idle=%d\n",
+ priv->staging_rxon.rx_chain,
+ active_rx_cnt, idle_rx_cnt);
+
+ WARN_ON(active_rx_cnt == 0 || idle_rx_cnt == 0 ||
+ active_rx_cnt < idle_rx_cnt);
}
EXPORT_SYMBOL(iwl_set_rxon_chain);
@@ -815,11 +829,10 @@ int iwl_setup_mac(struct iwl_priv *priv)
{
int ret;
struct ieee80211_hw *hw = priv->hw;
- hw->rate_control_algorithm = "iwl-4965-rs";
+ hw->rate_control_algorithm = "iwl-agn-rs";
/* Tell mac80211 our characteristics */
- hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
- IEEE80211_HW_SIGNAL_DBM |
+ hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
/* Default value; 4 EDCA QOS priorities */
hw->queues = 4;
@@ -828,6 +841,7 @@ int iwl_setup_mac(struct iwl_priv *priv)
hw->ampdu_queues = priv->cfg->mod_params->num_of_ampdu_queues;
hw->conf.beacon_int = 100;
+ hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index db66114f1e5..64f139e9744 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -95,6 +95,8 @@ struct iwl_hcmd_utils_ops {
void (*chain_noise_reset)(struct iwl_priv *priv);
void (*rts_tx_cmd_flag)(struct ieee80211_tx_info *info,
__le32 *tx_flags);
+ int (*calc_rssi)(struct iwl_priv *priv,
+ struct iwl_rx_phy_res *rx_resp);
};
struct iwl_lib_ops {
@@ -139,7 +141,6 @@ struct iwl_lib_ops {
int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src);
} apm_ops;
/* power */
- int (*set_power)(struct iwl_priv *priv, void *cmd);
int (*send_tx_power) (struct iwl_priv *priv);
void (*update_chain_flags)(struct iwl_priv *priv);
void (*temperature) (struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index 545ed692d88..52629fbd835 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -104,6 +104,7 @@
* 3-2: 0 = A, 1 = B, 2 = C, 3 = D step
*/
#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
+#define CSR_DBG_HPET_MEM_REG (CSR_BASE+0x240)
/* Bits for CSR_HW_IF_CONFIG_REG */
#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010)
@@ -118,7 +119,12 @@
#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000)
#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000)
-#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
+#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000)
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
+#define CSR_HW_IF_CONFIG_REG_BIT_PCI_OWN_SEM (0x00400000)
+#define CSR_HW_IF_CONFIG_REG_BIT_ME_OWN (0x02000000)
+#define CSR_HW_IF_CONFIG_REG_BIT_WAKE_ME (0x08000000)
+
/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
* acknowledged (reset) by host writing "1" to flagged bits. */
@@ -236,6 +242,8 @@
#define CSR39_ANA_PLL_CFG_VAL (0x01000000)
#define CSR50_ANA_PLL_CFG_VAL (0x00880300)
+/* HPET MEM debug */
+#define CSR_DBG_HPET_MEM_REG_VAL (0xFFFF0000)
/*=== HBUS (Host-side Bus) ===*/
#define HBUS_BASE (0x400)
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 58384805a49..d2daa174df2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -33,12 +33,12 @@
#define IWL_DEBUG(level, fmt, args...) \
do { if (priv->debug_level & (level)) \
dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \
- in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+ in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
#define IWL_DEBUG_LIMIT(level, fmt, args...) \
do { if ((priv->debug_level & (level)) && net_ratelimit()) \
dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \
- in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+ in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl_debugfs {
@@ -68,12 +68,8 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv);
#endif
#else
-static inline void IWL_DEBUG(int level, const char *fmt, ...)
-{
-}
-static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
-{
-}
+#define IWL_DEBUG(level, fmt, args...)
+#define IWL_DEBUG_LIMIT(level, fmt, args...)
#endif /* CONFIG_IWLWIFI_DEBUG */
@@ -118,7 +114,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
#define IWL_DL_MAC80211 (1 << 1)
#define IWL_DL_HOST_COMMAND (1 << 2)
#define IWL_DL_STATE (1 << 3)
-
+#define IWL_DL_MACDUMP (1 << 4)
#define IWL_DL_RADIO (1 << 7)
#define IWL_DL_POWER (1 << 8)
#define IWL_DL_TEMP (1 << 9)
@@ -158,6 +154,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
#define IWL_DEBUG_INFO(f, a...) IWL_DEBUG(IWL_DL_INFO, f, ## a)
#define IWL_DEBUG_MAC80211(f, a...) IWL_DEBUG(IWL_DL_MAC80211, f, ## a)
+#define IWL_DEBUG_MACDUMP(f, a...) IWL_DEBUG(IWL_DL_MACDUMP, f, ## a)
#define IWL_DEBUG_TEMP(f, a...) IWL_DEBUG(IWL_DL_TEMP, f, ## a)
#define IWL_DEBUG_SCAN(f, a...) IWL_DEBUG(IWL_DL_SCAN, f, ## a)
#define IWL_DEBUG_RX(f, a...) IWL_DEBUG(IWL_DL_RX, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index ed948dc59b3..20db0eb636a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -231,7 +231,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
DECLARE_MAC_BUF(mac);
buf = kmalloc(bufsz, GFP_KERNEL);
- if(!buf)
+ if (!buf)
return -ENOMEM;
pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n",
@@ -364,16 +364,19 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
{
struct iwl_debugfs *dbgfs;
struct dentry *phyd = priv->hw->wiphy->debugfsdir;
+ int ret = 0;
dbgfs = kzalloc(sizeof(struct iwl_debugfs), GFP_KERNEL);
if (!dbgfs) {
+ ret = -ENOMEM;
goto err;
}
priv->dbgfs = dbgfs;
dbgfs->name = name;
dbgfs->dir_drv = debugfs_create_dir(name, phyd);
- if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)){
+ if (!dbgfs->dir_drv || IS_ERR(dbgfs->dir_drv)) {
+ ret = -ENOENT;
goto err;
}
@@ -394,7 +397,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
err:
IWL_ERROR("Can't open the debugfs directory\n");
iwl_dbgfs_unregister(priv);
- return -ENOENT;
+ return ret;
}
EXPORT_SYMBOL(iwl_dbgfs_register);
@@ -404,7 +407,7 @@ EXPORT_SYMBOL(iwl_dbgfs_register);
*/
void iwl_dbgfs_unregister(struct iwl_priv *priv)
{
- if (!(priv->dbgfs))
+ if (!priv->dbgfs)
return;
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_eeprom);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 4d789e353e3..cdfb343c7ec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -36,7 +36,7 @@
#include <linux/kernel.h>
#include <net/ieee80211_radiotap.h>
-#define DRV_NAME "iwl4965"
+#define DRV_NAME "iwlagn"
#include "iwl-rfkill.h"
#include "iwl-eeprom.h"
#include "iwl-4965-hw.h"
@@ -45,6 +45,7 @@
#include "iwl-debug.h"
#include "iwl-led.h"
#include "iwl-power.h"
+#include "iwl-agn-rs.h"
/* configuration for the iwl4965 */
extern struct iwl_cfg iwl4965_agn_cfg;
@@ -134,8 +135,7 @@ struct iwl_tx_info {
struct iwl_tx_queue {
struct iwl_queue q;
struct iwl_tfd_frame *bd;
- struct iwl_cmd *cmd;
- dma_addr_t dma_addr_cmd;
+ struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS];
struct iwl_tx_info *txb;
int need_update;
int sched_retry;
@@ -191,7 +191,6 @@ struct iwl4965_clip_group {
const s8 clip_powers[IWL_MAX_RATES];
};
-#include "iwl-4965-rs.h"
#define IWL_TX_FIFO_AC0 0
#define IWL_TX_FIFO_AC1 1
@@ -219,7 +218,7 @@ enum iwl_pwr_src {
struct iwl_frame {
union {
struct ieee80211_hdr frame;
- struct iwl4965_tx_beacon_cmd beacon;
+ struct iwl_tx_beacon_cmd beacon;
u8 raw[IEEE80211_FRAME_LEN];
u8 cmd[360];
} u;
@@ -283,10 +282,9 @@ struct iwl_cmd {
u32 val32;
struct iwl4965_bt_cmd bt;
struct iwl4965_rxon_time_cmd rxon_time;
- struct iwl4965_powertable_cmd powertable;
+ struct iwl_powertable_cmd powertable;
struct iwl_qosparam_cmd qosparam;
struct iwl_tx_cmd tx;
- struct iwl4965_tx_beacon_cmd tx_beacon;
struct iwl4965_rxon_assoc_cmd rxon_assoc;
struct iwl_rem_sta_cmd rm_sta;
u8 *indirect;
@@ -414,7 +412,6 @@ struct iwl_ht_info {
/* self configuration data */
u8 is_ht;
u8 supported_chan_width;
- u16 tx_mimo_ps_mode;
u8 is_green_field;
u8 sgf; /* HT_SHORT_GI_* short guard interval */
u8 max_amsdu_size;
@@ -590,6 +587,7 @@ extern unsigned int iwl4965_fill_beacon_frame(struct iwl_priv *priv,
const u8 *dest, int left);
extern void iwl4965_update_chain_flags(struct iwl_priv *priv);
int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src);
+extern int iwl4965_set_power(struct iwl_priv *priv, void *cmd);
extern const u8 iwl_bcast_addr[ETH_ALEN];
@@ -642,10 +640,6 @@ struct iwl_priv;
* Forward declare iwl-4965.c functions for iwl-base.c
*/
extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv);
-
-int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw,
- enum ieee80211_ampdu_mlme_action action,
- const u8 *addr, u16 tid, u16 *ssn);
int iwl4965_check_empty_hw_queue(struct iwl_priv *priv, int sta_id,
u8 tid, int txq_id);
@@ -812,14 +806,11 @@ struct iwl_chain_noise_data {
#define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */
-#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
-
enum {
MEASUREMENT_READY = (1 << 0),
MEASUREMENT_ACTIVE = (1 << 1),
};
-#endif
#define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */
@@ -844,7 +835,7 @@ struct iwl_priv {
struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
-#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
/* spectrum measurement report caching */
struct iwl4965_spectrum_notification measure_report;
u8 measurement_status;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 4a08a1b5097..37155755efc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -63,7 +63,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <net/mac80211.h>
@@ -146,7 +145,7 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv)
{
u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
- IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+ IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x\n", gp);
return -ENOENT;
}
return 0;
@@ -227,7 +226,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
ret = priv->cfg->ops->lib->eeprom_ops.verify_signature(priv);
if (ret < 0) {
- IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+ IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x\n", gp);
ret = -ENOENT;
goto err;
}
@@ -254,7 +253,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
}
if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
- IWL_ERROR("Time out reading EEPROM[%d]", addr);
+ IWL_ERROR("Time out reading EEPROM[%d]\n", addr);
ret = -ETIMEDOUT;
goto done;
}
@@ -273,8 +272,7 @@ EXPORT_SYMBOL(iwl_eeprom_init);
void iwl_eeprom_free(struct iwl_priv *priv)
{
- if(priv->eeprom)
- kfree(priv->eeprom);
+ kfree(priv->eeprom);
priv->eeprom = NULL;
}
EXPORT_SYMBOL(iwl_eeprom_free);
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index 944642450d3..cd11c0ca299 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -287,6 +287,7 @@
#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000)
+#define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28
/**
* Transmit DMA Channel Control/Status Registers (TCSR)
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 8fa991b7202..2eb03eea190 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -28,7 +28,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <net/mac80211.h>
#include "iwl-dev.h" /* FIXME: remove */
@@ -228,7 +227,7 @@ cancel:
* TX cmd queue. Otherwise in case the cmd comes
* in later, it will possibly set an invalid
* address (cmd->meta.source). */
- qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
+ qcmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
qcmd->meta.flags &= ~CMD_WANT_SKB;
}
fail:
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 899d7a2567a..4eee1b163cd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
@@ -161,12 +160,32 @@ int iwl4965_led_off(struct iwl_priv *priv, int led_id)
/* Set led register off */
static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id)
{
- IWL_DEBUG_LED("radio off\n");
+ IWL_DEBUG_LED("LED Reg off\n");
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
return 0;
}
/*
+ * Set led register in case of disassociation according to rfkill state
+ */
+static int iwl_led_associate(struct iwl_priv *priv, int led_id)
+{
+ IWL_DEBUG_LED("Associated\n");
+ priv->allow_blinking = 1;
+ return iwl4965_led_on_reg(priv, led_id);
+}
+static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
+{
+ priv->allow_blinking = 0;
+ if (iwl_is_rfkill(priv))
+ iwl4965_led_off_reg(priv, led_id);
+ else
+ iwl4965_led_on_reg(priv, led_id);
+
+ return 0;
+}
+
+/*
* brightness call back function for Tx/Rx LED
*/
static int iwl_led_associated(struct iwl_priv *priv, int led_id)
@@ -199,16 +218,10 @@ static void iwl_led_brightness_set(struct led_classdev *led_cdev,
led_type_str[led->type], brightness);
switch (brightness) {
case LED_FULL:
- if (led->type == IWL_LED_TRG_ASSOC)
- priv->allow_blinking = 1;
-
if (led->led_on)
led->led_on(priv, IWL_LED_LINK);
break;
case LED_OFF:
- if (led->type == IWL_LED_TRG_ASSOC)
- priv->allow_blinking = 0;
-
if (led->led_off)
led->led_off(priv, IWL_LED_LINK);
break;
@@ -228,12 +241,12 @@ static void iwl_led_brightness_set(struct led_classdev *led_cdev,
*/
static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
enum led_type type, u8 set_led,
- const char *name, char *trigger)
+ char *trigger)
{
struct device *device = wiphy_dev(priv->hw->wiphy);
int ret;
- led->led_dev.name = name;
+ led->led_dev.name = led->name;
led->led_dev.brightness_set = iwl_led_brightness_set;
led->led_dev.default_trigger = trigger;
@@ -268,7 +281,9 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
if (tpt < 0) /* wrapparound */
tpt = -tpt;
- IWL_DEBUG_LED("tpt %lld current_tpt %lld\n", tpt, current_tpt);
+ IWL_DEBUG_LED("tpt %lld current_tpt %llu\n",
+ (long long)tpt,
+ (unsigned long long)current_tpt);
priv->led_tpt = current_tpt;
if (!priv->allow_blinking)
@@ -282,12 +297,6 @@ static int iwl_get_blink_rate(struct iwl_priv *priv)
return i;
}
-static inline int is_rf_kill(struct iwl_priv *priv)
-{
- return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
- test_bit(STATUS_RF_KILL_SW, &priv->status);
-}
-
/*
* this function called from handler. Since setting Led command can
* happen very frequent we postpone led command to be called from
@@ -301,7 +310,7 @@ void iwl_leds_background(struct iwl_priv *priv)
priv->last_blink_time = 0;
return;
}
- if (is_rf_kill(priv)) {
+ if (iwl_is_rfkill(priv)) {
priv->last_blink_time = 0;
return;
}
@@ -335,7 +344,6 @@ EXPORT_SYMBOL(iwl_leds_background);
int iwl_leds_register(struct iwl_priv *priv)
{
char *trigger;
- char name[32];
int ret;
priv->last_blink_rate = 0;
@@ -344,7 +352,8 @@ int iwl_leds_register(struct iwl_priv *priv)
priv->allow_blinking = 0;
trigger = ieee80211_get_radio_led_name(priv->hw);
- snprintf(name, sizeof(name), "iwl-%s:radio",
+ snprintf(priv->led[IWL_LED_TRG_RADIO].name,
+ sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s:radio",
wiphy_name(priv->hw->wiphy));
priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg;
@@ -352,31 +361,33 @@ int iwl_leds_register(struct iwl_priv *priv)
priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
- IWL_LED_TRG_RADIO, 1, name, trigger);
+ IWL_LED_TRG_RADIO, 1, trigger);
if (ret)
goto exit_fail;
trigger = ieee80211_get_assoc_led_name(priv->hw);
- snprintf(name, sizeof(name), "iwl-%s:assoc",
+ snprintf(priv->led[IWL_LED_TRG_ASSOC].name,
+ sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s:assoc",
wiphy_name(priv->hw->wiphy));
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC],
- IWL_LED_TRG_ASSOC, 0, name, trigger);
+ IWL_LED_TRG_ASSOC, 0, trigger);
/* for assoc always turn led on */
- priv->led[IWL_LED_TRG_ASSOC].led_on = iwl4965_led_on_reg;
- priv->led[IWL_LED_TRG_ASSOC].led_off = iwl4965_led_on_reg;
+ priv->led[IWL_LED_TRG_ASSOC].led_on = iwl_led_associate;
+ priv->led[IWL_LED_TRG_ASSOC].led_off = iwl_led_disassociate;
priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
if (ret)
goto exit_fail;
trigger = ieee80211_get_rx_led_name(priv->hw);
- snprintf(name, sizeof(name), "iwl-%s:RX", wiphy_name(priv->hw->wiphy));
-
+ snprintf(priv->led[IWL_LED_TRG_RX].name,
+ sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s:RX",
+ wiphy_name(priv->hw->wiphy));
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX],
- IWL_LED_TRG_RX, 0, name, trigger);
+ IWL_LED_TRG_RX, 0, trigger);
priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
@@ -386,9 +397,12 @@ int iwl_leds_register(struct iwl_priv *priv)
goto exit_fail;
trigger = ieee80211_get_tx_led_name(priv->hw);
- snprintf(name, sizeof(name), "iwl-%s:TX", wiphy_name(priv->hw->wiphy));
+ snprintf(priv->led[IWL_LED_TRG_TX].name,
+ sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s:TX",
+ wiphy_name(priv->hw->wiphy));
+
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX],
- IWL_LED_TRG_TX, 0, name, trigger);
+ IWL_LED_TRG_TX, 0, trigger);
priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index 1980ae5a7e8..588c9ad20e8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -52,6 +52,7 @@ enum led_type {
struct iwl_led {
struct iwl_priv *priv;
struct led_classdev led_dev;
+ char name[32];
int (*led_on) (struct iwl_priv *priv, int led_id);
int (*led_off) (struct iwl_priv *priv, int led_id);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 2e71803e09b..a099c9e30e5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -29,7 +29,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <net/mac80211.h>
@@ -82,7 +81,7 @@
/* default power management (not Tx power) table values */
/* for tim 0-10 */
-static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = {
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
@@ -93,7 +92,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
/* for tim = 3-10 */
-static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = {
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
@@ -103,7 +102,7 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
};
/* for tim > 11 */
-static struct iwl_power_vec_entry range_2[IWL_POWER_AC] = {
+static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = {
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
@@ -112,12 +111,19 @@ static struct iwl_power_vec_entry range_2[IWL_POWER_AC] = {
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
};
+/* set card power command */
+static int iwl_set_power(struct iwl_priv *priv, void *cmd)
+{
+ return iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD,
+ sizeof(struct iwl_powertable_cmd),
+ cmd, NULL);
+}
/* decide the right power level according to association status
* and battery status
*/
static u16 iwl_get_auto_power_mode(struct iwl_priv *priv)
{
- u16 mode = priv->power_data.user_power_setting;
+ u16 mode;
switch (priv->power_data.user_power_setting) {
case IWL_POWER_AUTO:
@@ -129,12 +135,16 @@ static u16 iwl_get_auto_power_mode(struct iwl_priv *priv)
else
mode = IWL_POWER_ON_AC_DISASSOC;
break;
+ /* FIXME: remove battery and ac from here */
case IWL_POWER_BATTERY:
mode = IWL_POWER_INDEX_3;
break;
case IWL_POWER_AC:
mode = IWL_POWER_MODE_CAM;
break;
+ default:
+ mode = priv->power_data.user_power_setting;
+ break;
}
return mode;
}
@@ -144,7 +154,7 @@ static int iwl_power_init_handle(struct iwl_priv *priv)
{
int ret = 0, i;
struct iwl_power_mgr *pow_data;
- int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC;
+ int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX;
u16 pci_pm;
IWL_DEBUG_POWER("Initialize power \n");
@@ -162,11 +172,11 @@ static int iwl_power_init_handle(struct iwl_priv *priv)
if (ret != 0)
return 0;
else {
- struct iwl4965_powertable_cmd *cmd;
+ struct iwl_powertable_cmd *cmd;
IWL_DEBUG_POWER("adjust power command flags\n");
- for (i = 0; i < IWL_POWER_AC; i++) {
+ for (i = 0; i < IWL_POWER_MAX; i++) {
cmd = &pow_data->pwr_range_0[i].cmd;
if (pci_pm & 0x1)
@@ -180,7 +190,7 @@ static int iwl_power_init_handle(struct iwl_priv *priv)
/* adjust power command according to dtim period and power level*/
static int iwl_update_power_command(struct iwl_priv *priv,
- struct iwl4965_powertable_cmd *cmd,
+ struct iwl_powertable_cmd *cmd,
u16 mode)
{
int ret = 0, i;
@@ -204,7 +214,7 @@ static int iwl_update_power_command(struct iwl_priv *priv,
range = &pow_data->pwr_range_2[0];
period = pow_data->dtim_period;
- memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd));
+ memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
if (period == 0) {
period = 1;
@@ -258,17 +268,18 @@ int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh)
* else user level */
switch (setting->system_power_setting) {
- case IWL_POWER_AUTO:
+ case IWL_POWER_SYS_AUTO:
final_mode = iwl_get_auto_power_mode(priv);
break;
- case IWL_POWER_BATTERY:
+ case IWL_POWER_SYS_BATTERY:
final_mode = IWL_POWER_INDEX_3;
break;
- case IWL_POWER_AC:
+ case IWL_POWER_SYS_AC:
final_mode = IWL_POWER_MODE_CAM;
break;
default:
- final_mode = setting->system_power_setting;
+ final_mode = IWL_POWER_INDEX_3;
+ WARN_ON(1);
}
if (setting->critical_power_setting > final_mode)
@@ -280,7 +291,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh)
if (!iwl_is_rfkill(priv) && !setting->power_disabled &&
((setting->power_mode != final_mode) || refresh)) {
- struct iwl4965_powertable_cmd cmd;
+ struct iwl_powertable_cmd cmd;
if (final_mode != IWL_POWER_MODE_CAM)
set_bit(STATUS_POWER_PMI, &priv->status);
@@ -291,8 +302,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, u8 refresh)
if (final_mode == IWL_POWER_INDEX_5)
cmd.flags |= IWL_POWER_FAST_PD;
- if (priv->cfg->ops->lib->set_power)
- ret = priv->cfg->ops->lib->set_power(priv, &cmd);
+ ret = iwl_set_power(priv, &cmd);
if (final_mode == IWL_POWER_MODE_CAM)
clear_bit(STATUS_POWER_PMI, &priv->status);
@@ -388,7 +398,7 @@ void iwl_power_initialize(struct iwl_priv *priv)
iwl_power_init_handle(priv);
priv->power_data.user_power_setting = IWL_POWER_AUTO;
priv->power_data.power_disabled = 0;
- priv->power_data.system_power_setting = IWL_POWER_AUTO;
+ priv->power_data.system_power_setting = IWL_POWER_SYS_AUTO;
priv->power_data.is_battery_active = 0;
priv->power_data.power_disabled = 0;
priv->power_data.critical_power_setting = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index b066724a1c2..abcbbf96a84 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -33,12 +33,25 @@
struct iwl_priv;
-#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */
-#define IWL_POWER_INDEX_3 0x03
-#define IWL_POWER_INDEX_5 0x05
-#define IWL_POWER_AC 0x06
-#define IWL_POWER_BATTERY 0x07
-#define IWL_POWER_AUTO 0x08
+enum {
+ IWL_POWER_MODE_CAM, /* Continuously Aware Mode, always on */
+ IWL_POWER_INDEX_1,
+ IWL_POWER_INDEX_2,
+ IWL_POWER_INDEX_3,
+ IWL_POWER_INDEX_4,
+ IWL_POWER_INDEX_5,
+ IWL_POWER_AUTO,
+ IWL_POWER_MAX = IWL_POWER_AUTO,
+ IWL_POWER_AC,
+ IWL_POWER_BATTERY,
+};
+
+enum {
+ IWL_POWER_SYS_AUTO,
+ IWL_POWER_SYS_AC,
+ IWL_POWER_SYS_BATTERY,
+};
+
#define IWL_POWER_LIMIT 0x08
#define IWL_POWER_MASK 0x0F
#define IWL_POWER_ENABLED 0x10
@@ -46,15 +59,15 @@ struct iwl_priv;
/* Power management (not Tx power) structures */
struct iwl_power_vec_entry {
- struct iwl4965_powertable_cmd cmd;
+ struct iwl_powertable_cmd cmd;
u8 no_dtim;
};
struct iwl_power_mgr {
spinlock_t lock;
- struct iwl_power_vec_entry pwr_range_0[IWL_POWER_AC];
- struct iwl_power_vec_entry pwr_range_1[IWL_POWER_AC];
- struct iwl_power_vec_entry pwr_range_2[IWL_POWER_AC];
+ struct iwl_power_vec_entry pwr_range_0[IWL_POWER_MAX];
+ struct iwl_power_vec_entry pwr_range_1[IWL_POWER_MAX];
+ struct iwl_power_vec_entry pwr_range_2[IWL_POWER_MAX];
u32 dtim_period;
/* final power level that used to calculate final power command */
u8 power_mode;
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 70d9c7568b9..ee5afd48d3a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -84,14 +84,16 @@
#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
-#define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000)
-#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
+#define APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS (0x00400000)
+#define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000)
+#define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000)
+#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
+#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */
+#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000)
-#define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000)
-#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
-#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x01000000)
+#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
/**
* BSM (Bootstrap State Machine)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
index e5e5846e9f2..5d642298f04 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c
@@ -27,7 +27,6 @@
*****************************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <net/mac80211.h>
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index e2d9afba38a..e81bfc42a7c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -791,7 +791,7 @@ static inline void iwl_dbg_report_frame(struct iwl_priv *priv,
static void iwl_add_radiotap(struct iwl_priv *priv,
struct sk_buff *skb,
- struct iwl4965_rx_phy_res *rx_start,
+ struct iwl_rx_phy_res *rx_start,
struct ieee80211_rx_status *stats,
u32 ampdu_status)
{
@@ -1010,8 +1010,8 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
struct ieee80211_rx_status *stats)
{
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
- struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
- (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
+ struct iwl_rx_phy_res *rx_start = (include_phy) ?
+ (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
struct ieee80211_hdr *hdr;
u16 len;
__le32 *rx_end;
@@ -1020,7 +1020,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
u32 ampdu_status_legacy;
if (!include_phy && priv->last_phy_res[0])
- rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
+ rx_start = (struct iwl_rx_phy_res *)&priv->last_phy_res[1];
if (!rx_start) {
IWL_ERROR("MPDU frame without a PHY data\n");
@@ -1032,8 +1032,8 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
len = le16_to_cpu(rx_start->byte_count);
- rx_end = (__le32 *) ((u8 *) &pkt->u.raw[0] +
- sizeof(struct iwl4965_rx_phy_res) +
+ rx_end = (__le32 *)((u8 *) &pkt->u.raw[0] +
+ sizeof(struct iwl_rx_phy_res) +
rx_start->cfg_phy_cnt + len);
} else {
@@ -1084,40 +1084,13 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
}
/* Calc max signal level (dBm) among 3 possible receivers */
-static int iwl_calc_rssi(struct iwl_priv *priv,
- struct iwl4965_rx_phy_res *rx_resp)
+static inline int iwl_calc_rssi(struct iwl_priv *priv,
+ struct iwl_rx_phy_res *rx_resp)
{
- /* data from PHY/DSP regarding signal strength, etc.,
- * contents are always there, not configurable by host. */
- struct iwl4965_rx_non_cfg_phy *ncphy =
- (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy;
- u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK)
- >> IWL_AGC_DB_POS;
-
- u32 valid_antennae =
- (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK)
- >> RX_PHY_FLAGS_ANTENNAE_OFFSET;
- u8 max_rssi = 0;
- u32 i;
-
- /* Find max rssi among 3 possible receivers.
- * These values are measured by the digital signal processor (DSP).
- * They should stay fairly constant even as the signal strength varies,
- * if the radio's automatic gain control (AGC) is working right.
- * AGC value (see below) will provide the "interesting" info. */
- for (i = 0; i < 3; i++)
- if (valid_antennae & (1 << i))
- max_rssi = max(ncphy->rssi_info[i << 1], max_rssi);
-
- IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n",
- ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4],
- max_rssi, agc);
-
- /* dBm = max_rssi dB - agc dB - constant.
- * Higher AGC (higher radio gain) means lower signal. */
- return max_rssi - agc - IWL_RSSI_OFFSET;
+ return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
}
+
static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
{
unsigned long flags;
@@ -1180,9 +1153,9 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
* this rx packet for legacy frames,
* or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
int include_phy = (pkt->hdr.cmd == REPLY_RX);
- struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
- (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) :
- (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
+ struct iwl_rx_phy_res *rx_start = (include_phy) ?
+ (struct iwl_rx_phy_res *)&(pkt->u.raw[0]) :
+ (struct iwl_rx_phy_res *)&priv->last_phy_res[1];
__le32 *rx_end;
unsigned int len = 0;
u16 fc;
@@ -1200,7 +1173,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
rx_status.antenna = 0;
rx_status.flag = 0;
- rx_status.flag |= RX_FLAG_TSFT;
+
+ /* TSF isn't reliable. In order to allow smooth user experience,
+ * this W/A doesn't propagate it to the mac80211 */
+ /*rx_status.flag |= RX_FLAG_TSFT;*/
if ((unlikely(rx_start->cfg_phy_cnt > 20))) {
IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n",
@@ -1210,7 +1186,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
if (!include_phy) {
if (priv->last_phy_res[0])
- rx_start = (struct iwl4965_rx_phy_res *)
+ rx_start = (struct iwl_rx_phy_res *)
&priv->last_phy_res[1];
else
rx_start = NULL;
@@ -1227,7 +1203,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
len = le16_to_cpu(rx_start->byte_count);
rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt +
- sizeof(struct iwl4965_rx_phy_res) + len);
+ sizeof(struct iwl_rx_phy_res) + len);
} else {
struct iwl4965_rx_mpdu_res_start *amsdu =
(struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
@@ -1316,6 +1292,6 @@ void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
priv->last_phy_res[0] = 1;
memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
- sizeof(struct iwl4965_rx_phy_res));
+ sizeof(struct iwl_rx_phy_res));
}
EXPORT_SYMBOL(iwl_rx_reply_rx_phy);
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index efc750d2fc5..6c8ac3a87d5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -202,6 +202,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv)
clear_bit(STATUS_SCAN_HW, &priv->status);
}
+ priv->alloc_rxb_skb--;
dev_kfree_skb_any(cmd.meta.u.skb);
return ret;
@@ -270,6 +271,7 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
+#ifdef CONFIG_IWLWIFI_DEBUG
struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
@@ -277,6 +279,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
scan_notif->scanned_channels,
scan_notif->tsf_low,
scan_notif->tsf_high, scan_notif->status);
+#endif
/* The HW is no longer scanning */
clear_bit(STATUS_SCAN_HW, &priv->status);
@@ -418,7 +421,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
- if ((scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) && n_probes)
+ if (n_probes)
scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
scan_ch->active_dwell = cpu_to_le16(active_dwell);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 6d1467d0bd9..6283a3a707f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -207,7 +207,7 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
case WLAN_HT_CAP_MIMO_PS_DISABLED:
break;
default:
- IWL_WARNING("Invalid MIMO PS mode %d", mimo_ps_mode);
+ IWL_WARNING("Invalid MIMO PS mode %d\n", mimo_ps_mode);
break;
}
@@ -823,7 +823,7 @@ int iwl_send_lq_cmd(struct iwl_priv *priv,
if (lq->sta_id == 0xFF)
lq->sta_id = IWL_AP_ID;
- iwl_dump_lq_cmd(priv,lq);
+ iwl_dump_lq_cmd(priv, lq);
if (iwl_is_associated(priv) && priv->assoc_station_added)
return iwl_send_cmd(priv, &cmd);
@@ -839,7 +839,7 @@ EXPORT_SYMBOL(iwl_send_lq_cmd);
* for automatic fallback during transmission.
*
* NOTE: This sets up a default set of values. These will be replaced later
- * if the driver's iwl-4965-rs rate scaling algorithm is used, instead of
+ * if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
* rc80211_simple.
*
* NOTE: Run REPLY_ADD_STA command to set up station table entry, before
@@ -969,7 +969,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
return priv->hw_params.bcast_sta_id;
default:
- IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
+ IWL_WARNING("Unknown mode of operation: %d\n", priv->iw_mode);
return priv->hw_params.bcast_sta_id;
}
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 9b50b1052b0..78b1a7a4ca4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -208,11 +208,12 @@ EXPORT_SYMBOL(iwl_txq_update_write_ptr);
* Free all buffers.
* 0-fill, but do not free "txq" descriptor structure.
*/
-static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id)
{
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
struct pci_dev *dev = priv->pci_dev;
- int len;
+ int i, slots_num, len;
if (q->n_bd == 0)
return;
@@ -227,7 +228,12 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
len += IWL_MAX_SCAN_SIZE;
/* De-alloc array of command/tx buffers */
- pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+ slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+ TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+ for (i = 0; i < slots_num; i++)
+ kfree(txq->cmd[i]);
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ kfree(txq->cmd[slots_num]);
/* De-alloc circular buffer of TFDs */
if (txq->q.n_bd)
@@ -396,13 +402,11 @@ static int iwl_hw_tx_queue_init(struct iwl_priv *priv,
/**
* iwl_tx_queue_init - Allocate and initialize one tx/cmd queue
*/
-static int iwl_tx_queue_init(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
+static int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id)
{
- struct pci_dev *dev = priv->pci_dev;
- int len;
- int rc = 0;
+ int i, len;
+ int ret;
/*
* Alloc buffer array for commands (Tx or other types of commands).
@@ -412,20 +416,25 @@ static int iwl_tx_queue_init(struct iwl_priv *priv,
* For normal Tx queues (all other queues), no super-size command
* space is needed.
*/
- len = sizeof(struct iwl_cmd) * slots_num;
- if (txq_id == IWL_CMD_QUEUE_NUM)
- len += IWL_MAX_SCAN_SIZE;
- txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
- if (!txq->cmd)
- return -ENOMEM;
+ len = sizeof(struct iwl_cmd);
+ for (i = 0; i <= slots_num; i++) {
+ if (i == slots_num) {
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ len += IWL_MAX_SCAN_SIZE;
+ else
+ continue;
+ }
+
+ txq->cmd[i] = kmalloc(len, GFP_KERNEL);
+ if (!txq->cmd[i])
+ goto err;
+ }
/* Alloc driver data array and TFD circular buffer */
- rc = iwl_tx_queue_alloc(priv, txq, txq_id);
- if (rc) {
- pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+ ret = iwl_tx_queue_alloc(priv, txq, txq_id);
+ if (ret)
+ goto err;
- return -ENOMEM;
- }
txq->need_update = 0;
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
@@ -439,6 +448,17 @@ static int iwl_tx_queue_init(struct iwl_priv *priv,
iwl_hw_tx_queue_init(priv, txq);
return 0;
+err:
+ for (i = 0; i < slots_num; i++) {
+ kfree(txq->cmd[i]);
+ txq->cmd[i] = NULL;
+ }
+
+ if (txq_id == IWL_CMD_QUEUE_NUM) {
+ kfree(txq->cmd[slots_num]);
+ txq->cmd[slots_num] = NULL;
+ }
+ return -ENOMEM;
}
/**
* iwl_hw_txq_ctx_free - Free TXQ Context
@@ -451,7 +471,7 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
/* Tx queues */
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
- iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+ iwl_tx_queue_free(priv, txq_id);
/* Keep-warm buffer */
iwl_kw_free(priv);
@@ -480,7 +500,7 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
/* Alloc keep-warm buffer */
ret = iwl_kw_alloc(priv);
if (ret) {
- IWL_ERROR("Keep Warm allocation failed");
+ IWL_ERROR("Keep Warm allocation failed\n");
goto error_kw;
}
spin_lock_irqsave(&priv->lock, flags);
@@ -751,20 +771,19 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_tfd_frame *tfd;
- u32 *control_flags;
- int txq_id = skb_get_queue_mapping(skb);
- struct iwl_tx_queue *txq = NULL;
- struct iwl_queue *q = NULL;
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+ struct iwl_cmd *out_cmd;
+ struct iwl_tx_cmd *tx_cmd;
+ int swq_id, txq_id;
dma_addr_t phys_addr;
dma_addr_t txcmd_phys;
dma_addr_t scratch_phys;
- struct iwl_cmd *out_cmd = NULL;
- struct iwl_tx_cmd *tx_cmd;
u16 len, idx, len_org;
u16 seq_number = 0;
- u8 id, hdr_len, unicast;
- u8 sta_id;
__le16 fc;
+ u8 hdr_len, unicast;
+ u8 sta_id;
u8 wait_write_ptr = 0;
u8 tid = 0;
u8 *qc = NULL;
@@ -789,7 +808,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
}
unicast = !is_multicast_ether_addr(hdr->addr1);
- id = 0;
fc = hdr->frame_control;
@@ -827,14 +845,16 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX("station Id %d\n", sta_id);
+ swq_id = skb_get_queue_mapping(skb);
+ txq_id = swq_id;
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & 0xf;
- seq_number = priv->stations[sta_id].tid[tid].seq_number &
- IEEE80211_SCTL_SEQ;
- hdr->seq_ctrl = cpu_to_le16(seq_number) |
- (hdr->seq_ctrl &
- __constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
+ seq_number = priv->stations[sta_id].tid[tid].seq_number;
+ seq_number &= IEEE80211_SCTL_SEQ;
+ hdr->seq_ctrl = hdr->seq_ctrl &
+ __constant_cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(seq_number);
seq_number += 0x10;
/* aggregation is on for this <sta,tid> */
if (info->flags & IEEE80211_TX_CTL_AMPDU)
@@ -851,7 +871,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Set up first empty TFD within this queue's circular TFD buffer */
tfd = &txq->bd[q->write_ptr];
memset(tfd, 0, sizeof(*tfd));
- control_flags = (u32 *) tfd;
idx = get_cmd_index(q, q->write_ptr, 0);
/* Set up driver data for this TFD */
@@ -859,7 +878,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
txq->txb[q->write_ptr].skb[0] = skb;
/* Set up first empty entry in queue's array of Tx/cmd buffers */
- out_cmd = &txq->cmd[idx];
+ out_cmd = txq->cmd[idx];
tx_cmd = &out_cmd->cmd.tx;
memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
@@ -899,14 +918,15 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Physical address of this Tx command's header (not MAC header!),
* within command buffer array. */
- txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
- offsetof(struct iwl_cmd, hdr);
+ txcmd_phys = pci_map_single(priv->pci_dev, out_cmd,
+ sizeof(struct iwl_cmd), PCI_DMA_TODEVICE);
+ txcmd_phys += offsetof(struct iwl_cmd, hdr);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
- if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
+ if (info->control.hw_key)
iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
/* Set up TFD's 2nd entry to point directly to remainder of skb,
@@ -962,16 +982,15 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (ret)
return ret;
- if ((iwl_queue_space(q) < q->high_mark)
- && priv->mac80211_registered) {
+ if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
if (wait_write_ptr) {
spin_lock_irqsave(&priv->lock, flags);
txq->need_update = 1;
iwl_txq_update_write_ptr(priv, txq);
spin_unlock_irqrestore(&priv->lock, flags);
+ } else {
+ ieee80211_stop_queue(priv->hw, swq_id);
}
-
- ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb));
}
return 0;
@@ -999,13 +1018,12 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
struct iwl_queue *q = &txq->q;
struct iwl_tfd_frame *tfd;
- u32 *control_flags;
struct iwl_cmd *out_cmd;
- u32 idx;
- u16 fix_size;
dma_addr_t phys_addr;
- int ret;
unsigned long flags;
+ int len, ret;
+ u32 idx;
+ u16 fix_size;
cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
@@ -1031,10 +1049,9 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
tfd = &txq->bd[q->write_ptr];
memset(tfd, 0, sizeof(*tfd));
- control_flags = (u32 *) tfd;
idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE);
- out_cmd = &txq->cmd[idx];
+ out_cmd = txq->cmd[idx];
out_cmd->hdr.cmd = cmd->id;
memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
@@ -1048,9 +1065,11 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
INDEX_TO_SEQ(q->write_ptr));
if (out_cmd->meta.flags & CMD_SIZE_HUGE)
out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
-
- phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
- offsetof(struct iwl_cmd, hdr);
+ len = (idx == TFD_CMD_SLOTS) ?
+ IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd);
+ phys_addr = pci_map_single(priv->pci_dev, out_cmd, len,
+ PCI_DMA_TODEVICE);
+ phys_addr += offsetof(struct iwl_cmd, hdr);
iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
@@ -1115,6 +1134,9 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
{
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
+ struct iwl_tfd_frame *bd = &txq->bd[index];
+ dma_addr_t dma_addr;
+ int is_odd, buf_len;
int nfreed = 0;
if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
@@ -1132,6 +1154,19 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
q->write_ptr, q->read_ptr);
queue_work(priv->workqueue, &priv->restart);
}
+ is_odd = (index/2) & 0x1;
+ if (is_odd) {
+ dma_addr = IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
+ (IWL_GET_BITS(bd->pa[index],
+ tb2_addr_hi20) << 16);
+ buf_len = IWL_GET_BITS(bd->pa[index], tb2_len);
+ } else {
+ dma_addr = le32_to_cpu(bd->pa[index].tb1_addr);
+ buf_len = IWL_GET_BITS(bd->pa[index], tb1_len);
+ }
+
+ pci_unmap_single(priv->pci_dev, dma_addr, buf_len,
+ PCI_DMA_TODEVICE);
nfreed++;
}
}
@@ -1163,7 +1198,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
- cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+ cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
/* Input error checking is done when commands are added to queue. */
if (cmd->meta.flags & CMD_WANT_SKB) {
@@ -1391,7 +1426,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
/* For each frame attempted in aggregation,
* update driver's record of tx frame's status. */
for (i = 0; i < agg->frame_count ; i++) {
- ack = bitmap & (1 << i);
+ ack = bitmap & (1ULL << i);
successes += !!ack;
IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff,
@@ -1435,7 +1470,7 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
if (scd_flow >= priv->hw_params.max_txq_num) {
- IWL_ERROR("BUG_ON scd_flow is bigger than number of queues");
+ IWL_ERROR("BUG_ON scd_flow is bigger than number of queues\n");
return;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 4a22d3fba75..b775d5bab66 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -29,7 +29,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
@@ -275,10 +274,8 @@ static int iwl3945_tx_queue_alloc(struct iwl3945_priv *priv,
return 0;
error:
- if (txq->txb) {
- kfree(txq->txb);
- txq->txb = NULL;
- }
+ kfree(txq->txb);
+ txq->txb = NULL;
return -ENOMEM;
}
@@ -365,10 +362,8 @@ void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *t
txq->q.n_bd, txq->bd, txq->q.dma_addr);
/* De-alloc array of per-TFD driver data */
- if (txq->txb) {
- kfree(txq->txb);
- txq->txb = NULL;
- }
+ kfree(txq->txb);
+ txq->txb = NULL;
/* 0-fill queue descriptor structure */
memset(txq, 0, sizeof(*txq));
@@ -1562,7 +1557,7 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv)
BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
- IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+ IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x\n", gp);
return -ENOENT;
}
@@ -1587,7 +1582,7 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv)
}
if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
- IWL_ERROR("Time out reading EEPROM[%d]", addr);
+ IWL_ERROR("Time out reading EEPROM[%d]\n", addr);
return -ETIMEDOUT;
}
e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
@@ -2511,7 +2506,7 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h
return priv->hw_setting.bcast_sta_id;
default:
- IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
+ IWL_WARNING("Unknown mode of operation: %d\n", priv->iw_mode);
return priv->hw_setting.bcast_sta_id;
}
}
@@ -2667,7 +2662,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb)
* first entry */
iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
- if (!(info->flags & IEEE80211_TX_CTL_DO_NOT_ENCRYPT))
+ if (info->control.hw_key)
iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0);
/* Set up TFD's 2nd entry to point directly to remainder of skb,
@@ -2703,9 +2698,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb)
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
- if (qc) {
+ if (qc)
priv->stations[sta_id].tid[tid].seq_number = seq_number;
- }
} else {
wait_write_ptr = 1;
txq->need_update = 0;
@@ -3813,7 +3807,7 @@ int iwl3945_calc_db_from_ratio(int sig_ratio)
/* 100:1 or higher, divide by 10 and use table,
* add 20 dB to make up for divide by 10 */
if (sig_ratio >= 100)
- return (20 + (int)ratio2dB[sig_ratio/10]);
+ return 20 + (int)ratio2dB[sig_ratio/10];
/* We shouldn't see this */
if (sig_ratio < 1)
@@ -5088,7 +5082,7 @@ static void iwl3945_dealloc_ucode_pci(struct iwl3945_priv *priv)
* iwl3945_verify_inst_full - verify runtime uCode image in card vs. host,
* looking at all data.
*/
-static int iwl3945_verify_inst_full(struct iwl3945_priv *priv, __le32 * image, u32 len)
+static int iwl3945_verify_inst_full(struct iwl3945_priv *priv, __le32 *image, u32 len)
{
u32 val;
u32 save_len = len;
@@ -5237,7 +5231,7 @@ static int iwl3945_verify_bsm(struct iwl3945_priv *priv)
val = iwl3945_read_prph(priv, BSM_WR_DWCOUNT_REG);
for (reg = BSM_SRAM_LOWER_BOUND;
reg < BSM_SRAM_LOWER_BOUND + len;
- reg += sizeof(u32), image ++) {
+ reg += sizeof(u32), image++) {
val = iwl3945_read_prph(priv, reg);
if (val != le32_to_cpu(*image)) {
IWL_ERROR("BSM uCode verification failed at "
@@ -6336,7 +6330,7 @@ static void iwl3945_bg_post_associate(struct work_struct *data)
DECLARE_MAC_BUF(mac);
if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
- IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
+ IWL_ERROR("%s Should not be called in AP mode\n", __func__);
return;
}
@@ -6417,7 +6411,7 @@ static void iwl3945_bg_post_associate(struct work_struct *data)
default:
IWL_ERROR("%s Should not be called in %d mode\n",
- __FUNCTION__, priv->iw_mode);
+ __func__, priv->iw_mode);
break;
}
@@ -6594,12 +6588,6 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
IWL_DEBUG_MAC80211("enter\n");
- if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
- IWL_DEBUG_MAC80211("leave - monitor\n");
- dev_kfree_skb_any(skb);
- return 0;
- }
-
IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
@@ -7456,7 +7444,7 @@ static ssize_t show_measurement(struct device *d,
struct iwl3945_priv *priv = dev_get_drvdata(d);
struct iwl3945_spectrum_notification measure_report;
u32 size = sizeof(measure_report), len = 0, ofs = 0;
- u8 *data = (u8 *) & measure_report;
+ u8 *data = (u8 *)&measure_report;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
@@ -7627,7 +7615,7 @@ static ssize_t show_power_level(struct device *d,
else
p += sprintf(p, " \n");
- return (p - buf + 1);
+ return p - buf + 1;
}
@@ -7649,7 +7637,7 @@ static ssize_t show_statistics(struct device *d,
struct iwl3945_priv *priv = dev_get_drvdata(d);
u32 size = sizeof(struct iwl3945_notif_statistics);
u32 len = 0, ofs = 0;
- u8 *data = (u8 *) & priv->statistics;
+ u8 *data = (u8 *)&priv->statistics;
int rc = 0;
if (!iwl3945_is_alive(priv))
@@ -7899,8 +7887,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->ibss_beacon = NULL;
/* Tell mac80211 our characteristics */
- hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
- IEEE80211_HW_SIGNAL_DBM |
+ hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
/* 4 EDCA QOS priorities */
@@ -8004,16 +7991,16 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
/* nic init */
iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS,
- CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
-
- iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
- err = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
- if (err < 0) {
- IWL_DEBUG_INFO("Failed to init the card\n");
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+ iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ err = iwl3945_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (err < 0) {
+ IWL_DEBUG_INFO("Failed to init the card\n");
goto out_remove_sysfs;
- }
+ }
/* Read the EEPROM */
err = iwl3945_eeprom_init(priv);
if (err) {
@@ -8115,9 +8102,8 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
iwl3945_unset_hw_setting(priv);
iwl3945_clear_stations_table(priv);
- if (priv->mac80211_registered) {
+ if (priv->mac80211_registered)
ieee80211_unregister_hw(priv->hw);
- }
/*netif_stop_queue(dev); */
flush_workqueue(priv->workqueue);
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 04d7a251e3f..8941919001b 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -595,7 +595,7 @@ static int if_cs_prog_helper(struct if_cs_card *card)
if (ret < 0) {
lbs_pr_err("can't download helper at 0x%x, ret %d\n",
sent, ret);
- goto done;
+ goto err_release;
}
if (count == 0)
@@ -604,9 +604,8 @@ static int if_cs_prog_helper(struct if_cs_card *card)
sent += count;
}
+err_release:
release_firmware(fw);
- ret = 0;
-
done:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
return ret;
@@ -676,14 +675,8 @@ static int if_cs_prog_real(struct if_cs_card *card)
}
ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
- if (ret < 0) {
+ if (ret < 0)
lbs_pr_err("firmware download failed\n");
- goto err_release;
- }
-
- ret = 0;
- goto done;
-
err_release:
release_firmware(fw);
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 14d5d61cec4..bd32ac0b4e0 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -297,9 +297,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
lbs_add_rtap(priv);
}
priv->monitormode = monitor_mode;
- }
-
- else {
+ } else {
if (!priv->monitormode)
return strlen(buf);
priv->monitormode = 0;
@@ -1242,8 +1240,6 @@ int lbs_start_card(struct lbs_private *priv)
lbs_pr_err("cannot register ethX device\n");
goto done;
}
- if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
- lbs_pr_err("cannot register lbs_rtap attribute\n");
lbs_update_channel(priv);
@@ -1275,6 +1271,13 @@ int lbs_start_card(struct lbs_private *priv)
if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
lbs_pr_err("cannot register lbs_mesh attribute\n");
+
+ /* While rtap isn't related to mesh, only mesh-enabled
+ * firmware implements the rtap functionality via
+ * CMD_802_11_MONITOR_MODE.
+ */
+ if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
+ lbs_pr_err("cannot register lbs_rtap attribute\n");
}
}
@@ -1306,9 +1309,9 @@ void lbs_stop_card(struct lbs_private *priv)
netif_carrier_off(priv->dev);
lbs_debugfs_remove_one(priv);
- device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
if (priv->mesh_tlv) {
device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
+ device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
}
/* Flush pending command nodes */
diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c
index 6d0ff8decaf..3309a9c3cfe 100644
--- a/drivers/net/wireless/libertas/persistcfg.c
+++ b/drivers/net/wireless/libertas/persistcfg.c
@@ -48,7 +48,7 @@ static ssize_t bootflag_get(struct device *dev,
if (ret)
return ret;
- return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag));
+ return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
}
/**
@@ -63,8 +63,8 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
int ret;
memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%x", &datum);
- if (ret != 1)
+ ret = sscanf(buf, "%d", &datum);
+ if ((ret != 1) || (datum > 1))
return -EINVAL;
*((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
@@ -91,7 +91,7 @@ static ssize_t boottime_get(struct device *dev,
if (ret)
return ret;
- return snprintf(buf, 12, "0x%x\n", defs.boottime);
+ return snprintf(buf, 12, "%d\n", defs.boottime);
}
/**
@@ -106,8 +106,8 @@ static ssize_t boottime_set(struct device *dev,
int ret;
memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%x", &datum);
- if (ret != 1)
+ ret = sscanf(buf, "%d", &datum);
+ if ((ret != 1) || (datum > 255))
return -EINVAL;
/* A too small boot time will result in the device booting into
@@ -143,7 +143,7 @@ static ssize_t channel_get(struct device *dev,
if (ret)
return ret;
- return snprintf(buf, 12, "0x%x\n", le16_to_cpu(defs.channel));
+ return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
}
/**
@@ -154,11 +154,11 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
{
struct lbs_private *priv = to_net_dev(dev)->priv;
struct cmd_ds_mesh_config cmd;
- uint16_t datum;
+ uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%hx", &datum);
+ ret = sscanf(buf, "%d", &datum);
if (ret != 1 || datum < 1 || datum > 11)
return -EINVAL;
@@ -274,8 +274,8 @@ static ssize_t protocol_id_set(struct device *dev,
int ret;
memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%x", &datum);
- if (ret != 1)
+ ret = sscanf(buf, "%d", &datum);
+ if ((ret != 1) || (datum > 255))
return -EINVAL;
/* fetch all other Information Element parameters */
@@ -328,8 +328,8 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
int ret;
memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%x", &datum);
- if (ret != 1)
+ ret = sscanf(buf, "%d", &datum);
+ if ((ret != 1) || (datum > 255))
return -EINVAL;
/* fetch all other Information Element parameters */
@@ -382,8 +382,8 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
int ret;
memset(&cmd, 0, sizeof(cmd));
- ret = sscanf(buf, "%x", &datum);
- if (ret != 1)
+ ret = sscanf(buf, "%d", &datum);
+ if ((ret != 1) || (datum > 255))
return -EINVAL;
/* fetch all other Information Element parameters */
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 5816230d58f..248d31a7aa3 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -500,7 +500,7 @@ failed_hw:
device_unregister(data->dev);
failed_drvdata:
ieee80211_free_hw(hw);
- hwsim_radios[i] = 0;
+ hwsim_radios[i] = NULL;
failed:
mac80211_hwsim_free();
return err;
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index b047306bf38..36c004e1560 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -1970,6 +1970,9 @@ __orinoco_set_multicast_list(struct net_device *dev)
priv->promiscuous = promisc;
}
+ /* If we're not in promiscuous mode, then we need to set the
+ * group address if either we want to multicast, or if we were
+ * multicasting and want to stop */
if (! promisc && (mc_count || priv->mc_count) ) {
struct dev_mc_list *p = dev->mc_list;
struct hermes_multicast mclist;
@@ -1989,22 +1992,16 @@ __orinoco_set_multicast_list(struct net_device *dev)
printk(KERN_WARNING "%s: Multicast list is "
"longer than mc_count\n", dev->name);
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES,
- HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN),
- &mclist);
+ err = hermes_write_ltv(hw, USER_BAP,
+ HERMES_RID_CNFGROUPADDRESSES,
+ HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
+ &mclist);
if (err)
printk(KERN_ERR "%s: Error %d setting multicast list.\n",
dev->name, err);
else
priv->mc_count = mc_count;
}
-
- /* Since we can set the promiscuous flag when it wasn't asked
- for, make sure the net_device knows about it. */
- if (priv->promiscuous)
- dev->flags |= IFF_PROMISC;
- else
- dev->flags &= ~IFF_PROMISC;
}
/* This must be called from user context, without locks held - use
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index c6f27b9022f..4801a363507 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -52,6 +52,8 @@ struct p54_common {
int (*open)(struct ieee80211_hw *dev);
void (*stop)(struct ieee80211_hw *dev);
int mode;
+ u16 seqno;
+ struct mutex conf_mutex;
u8 mac_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
struct pda_iq_autocal_entry *iq_autocal;
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index ffaf7a6b681..29be3dc8ee0 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -413,12 +413,12 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
last_addr = range->end_addr;
__skb_unlink(entry, &priv->tx_queue);
memset(&info->status, 0, sizeof(info->status));
- priv->tx_stats[skb_get_queue_mapping(skb)].len--;
entry_hdr = (struct p54_control_hdr *) entry->data;
entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
pad = entry_data->align[0];
+ priv->tx_stats[entry_data->hw_queue - 4].len--;
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
if (!(payload->status & 0x01))
info->flags |= IEEE80211_TX_STAT_ACK;
@@ -553,9 +553,11 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
struct ieee80211_tx_queue_stats *current_queue;
struct p54_common *priv = dev->priv;
struct p54_control_hdr *hdr;
+ struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
struct p54_tx_control_allocdata *txhdr;
size_t padding, len;
u8 rate;
+ u8 cts_rate = 0x20;
current_queue = &priv->tx_stats[skb_get_queue_mapping(skb)];
if (unlikely(current_queue->len > current_queue->limit))
@@ -580,31 +582,44 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
hdr->retry1 = hdr->retry2 = info->control.retry_limit;
- memset(txhdr->wep_key, 0x0, 16);
- txhdr->padding = 0;
- txhdr->padding2 = 0;
-
/* TODO: add support for alternate retry TX rates */
rate = ieee80211_get_tx_rate(dev, info)->hw_value;
- if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
+ if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) {
rate |= 0x10;
- if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+ cts_rate |= 0x10;
+ }
+ if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
rate |= 0x40;
- else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+ cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
+ } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
rate |= 0x20;
+ cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
+ }
memset(txhdr->rateset, rate, 8);
- txhdr->wep_key_present = 0;
- txhdr->wep_key_len = 0;
- txhdr->frame_type = cpu_to_le32(skb_get_queue_mapping(skb) + 4);
- txhdr->magic4 = 0;
- txhdr->antenna = (info->antenna_sel_tx == 0) ?
+ txhdr->key_type = 0;
+ txhdr->key_len = 0;
+ txhdr->hw_queue = skb_get_queue_mapping(skb) + 4;
+ txhdr->tx_antenna = (info->antenna_sel_tx == 0) ?
2 : info->antenna_sel_tx - 1;
txhdr->output_power = 0x7f; // HW Maximum
- txhdr->magic5 = (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
- 0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23));
+ txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
+ 0 : cts_rate;
if (padding)
txhdr->align[0] = padding;
+ /* FIXME: The sequence that follows is needed for this driver to
+ * work with mac80211 since "mac80211: fix TX sequence numbers".
+ * As with the temporary code in rt2x00, changes will be needed
+ * to get proper sequence numbers on beacons. In addition, this
+ * patch places the sequence number in the hardware state, which
+ * limits us to a single virtual state.
+ */
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+ priv->seqno += 0x10;
+ ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
+ }
/* modifies skb->cb and with it info, so must be last! */
p54_assign_address(dev, skb, hdr, skb->len);
@@ -803,8 +818,8 @@ static void p54_set_vdcf(struct ieee80211_hw *dev)
if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
vdcf->slottime = 9;
- vdcf->magic1 = 0x00;
- vdcf->magic2 = 0x10;
+ vdcf->magic1 = 0x10;
+ vdcf->magic2 = 0x00;
} else {
vdcf->slottime = 20;
vdcf->magic1 = 0x0a;
@@ -822,10 +837,21 @@ static int p54_start(struct ieee80211_hw *dev)
struct p54_common *priv = dev->priv;
int err;
+ if (!priv->cached_vdcf) {
+ priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf)+
+ priv->tx_hdr_len + sizeof(struct p54_control_hdr),
+ GFP_KERNEL);
+
+ if (!priv->cached_vdcf)
+ return -ENOMEM;
+ }
+
err = priv->open(dev);
if (!err)
priv->mode = IEEE80211_IF_TYPE_MNTR;
+ p54_init_vdcf(dev);
+
return err;
}
@@ -886,9 +912,12 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
{
int ret;
+ struct p54_common *priv = dev->priv;
+ mutex_lock(&priv->conf_mutex);
ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq));
p54_set_vdcf(dev);
+ mutex_unlock(&priv->conf_mutex);
return ret;
}
@@ -898,10 +927,12 @@ static int p54_config_interface(struct ieee80211_hw *dev,
{
struct p54_common *priv = dev->priv;
+ mutex_lock(&priv->conf_mutex);
p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642);
p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0);
p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+ mutex_unlock(&priv->conf_mutex);
return 0;
}
@@ -1000,15 +1031,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
sizeof(struct p54_tx_control_allocdata);
- priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf) +
- priv->tx_hdr_len + sizeof(struct p54_control_hdr), GFP_KERNEL);
-
- if (!priv->cached_vdcf) {
- ieee80211_free_hw(dev);
- return NULL;
- }
-
- p54_init_vdcf(dev);
+ mutex_init(&priv->conf_mutex);
return dev;
}
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
index 2245fcce92d..8db6c0e8e54 100644
--- a/drivers/net/wireless/p54/p54common.h
+++ b/drivers/net/wireless/p54/p54common.h
@@ -183,16 +183,16 @@ struct p54_frame_sent_hdr {
struct p54_tx_control_allocdata {
u8 rateset[8];
- u16 padding;
- u8 wep_key_present;
- u8 wep_key_len;
- u8 wep_key[16];
- __le32 frame_type;
- u32 padding2;
- __le16 magic4;
- u8 antenna;
+ u8 unalloc0[2];
+ u8 key_type;
+ u8 key_len;
+ u8 key[16];
+ u8 hw_queue;
+ u8 unalloc1[9];
+ u8 tx_antenna;
u8 output_power;
- __le32 magic5;
+ u8 cts_rate;
+ u8 unalloc2[3];
u8 align[0];
} __attribute__ ((packed));
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 815c095ef79..cbaca23a945 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -109,7 +109,17 @@ static void p54u_rx_cb(struct urb *urb)
urb->context = skb;
skb_queue_tail(&priv->rx_queue, skb);
} else {
+ if (!priv->hw_type)
+ skb_push(skb, sizeof(struct net2280_tx_hdr));
+
+ skb_reset_tail_pointer(skb);
skb_trim(skb, 0);
+ if (urb->transfer_buffer != skb_tail_pointer(skb)) {
+ /* this should not happen */
+ WARN_ON(1);
+ urb->transfer_buffer = skb_tail_pointer(skb);
+ }
+
skb_queue_tail(&priv->rx_queue, skb);
}
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 97fa14e0a47..3d75a7137d3 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -2518,7 +2518,7 @@ enum {
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+ offsetof(struct prism2_hostapd_param, u.generic_elem.data)
/* Maximum length for algorithm names (-1 for nul termination)
* used in ioctl() */
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index aa6dfb811c7..181a146b476 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1220,6 +1220,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
rt2x00_desc_write(txd, 0, word);
}
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 3558cb21074..cd5af656932 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -633,6 +633,16 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
rt2x00dev->link.vgc_level = value;
}
+/*
+ * NOTE: This function is directly ported from legacy driver, but
+ * despite it being declared it was never called. Although link tuning
+ * sounds like a good idea, and usually works well for the other drivers,
+ * it does _not_ work with rt2500usb. Enabling this function will result
+ * in TX capabilities only until association kicks in. Immediately
+ * after the successful association all TX frames will be kept in the
+ * hardware queue and never transmitted.
+ */
+#if 0
static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev)
{
int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
@@ -752,6 +762,9 @@ dynamic_cca_tune:
rt2x00dev->link.vgc_level = r17;
}
}
+#else
+#define rt2500usb_link_tuner NULL
+#endif
/*
* Initialization functions.
@@ -1121,6 +1134,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
int pipe = usb_sndbulkpipe(usb_dev, 1);
int length;
u16 reg;
+ u32 word, len;
/*
* Add the descriptor in front of the skb.
@@ -1130,6 +1144,17 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
skbdesc->desc = entry->skb->data;
/*
+ * Adjust the beacon databyte count. The current number is
+ * calculated before this function gets called, but falsely
+ * assumes that the descriptor was already present in the SKB.
+ */
+ rt2x00_desc_read(skbdesc->desc, 0, &word);
+ len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT);
+ len += skbdesc->desc_len;
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len);
+ rt2x00_desc_write(skbdesc->desc, 0, word);
+
+ /*
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
*/
@@ -1364,6 +1389,9 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp);
rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word);
+ } else {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &word);
@@ -1372,9 +1400,6 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41);
rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word);
EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word);
- } else {
- rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word);
@@ -1650,7 +1675,6 @@ static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
* Initialize all hw fields.
*/
rt2x00dev->hw->flags =
- IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM;
@@ -1726,6 +1750,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
__set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags);
+ __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
/*
* Set the rssi offset.
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 07b03b3c7ef..8b10ea41b20 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -108,7 +108,10 @@
#define SHORT_PIFS ( SIFS + SHORT_SLOT_TIME )
#define DIFS ( PIFS + SLOT_TIME )
#define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME )
-#define EIFS ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) )
+#define EIFS ( SIFS + DIFS + \
+ (8 * (IEEE80211_HEADER + ACK_SIZE)) )
+#define SHORT_EIFS ( SIFS + SHORT_DIFS + \
+ (8 * (IEEE80211_HEADER + ACK_SIZE)) )
/*
* Chipset identification
@@ -365,6 +368,12 @@ struct rt2x00_intf {
#define DELAYED_CONFIG_ERP 0x00000002
#define DELAYED_LED_ASSOC 0x00000004
+ /*
+ * Software sequence counter, this is only required
+ * for hardware which doesn't support hardware
+ * sequence counting.
+ */
+ spinlock_t seqlock;
u16 seqno;
};
@@ -597,6 +606,7 @@ enum rt2x00_flags {
DEVICE_STARTED_SUSPEND,
DEVICE_ENABLED_RADIO,
DEVICE_DISABLED_RADIO_HW,
+ DEVICE_DIRTY_CONFIG,
/*
* Driver features
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index f20ca712504..d134c3be539 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -254,6 +254,8 @@ config:
libconf.ant.rx = default_ant->rx;
else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
libconf.ant.rx = ANTENNA_B;
+ else
+ libconf.ant.rx = active_ant->rx;
if (conf->antenna_sel_tx)
libconf.ant.tx = conf->antenna_sel_tx;
@@ -261,6 +263,8 @@ config:
libconf.ant.tx = default_ant->tx;
else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
libconf.ant.tx = ANTENNA_B;
+ else
+ libconf.ant.tx = active_ant->tx;
}
if (flags & CONFIG_UPDATE_SLOT_TIME) {
@@ -271,7 +275,7 @@ config:
libconf.sifs = SIFS;
libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS;
libconf.difs = short_slot_time ? SHORT_DIFS : DIFS;
- libconf.eifs = EIFS;
+ libconf.eifs = short_slot_time ? SHORT_EIFS : EIFS;
}
libconf.conf = conf;
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 300cf061035..6bee1d611bb 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -372,9 +372,6 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \
if (*offset) \
return 0; \
\
- if (!capable(CAP_NET_ADMIN)) \
- return -EPERM; \
- \
if (intf->offset_##__name >= debug->__name.word_count) \
return -EINVAL; \
\
@@ -454,7 +451,7 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name,
data += sprintf(data, "compiled: %s %s\n", __DATE__, __TIME__);
blob->size = strlen(blob->data);
- return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
+ return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
}
static struct dentry *rt2x00debug_create_file_chipset(const char *name,
@@ -482,7 +479,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
data += sprintf(data, "rf length: %d\n", debug->rf.word_count);
blob->size = strlen(blob->data);
- return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
+ return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
}
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
@@ -517,7 +514,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
if (IS_ERR(intf->chipset_entry))
goto exit;
- intf->dev_flags = debugfs_create_file("dev_flags", S_IRUGO,
+ intf->dev_flags = debugfs_create_file("dev_flags", S_IRUSR,
intf->driver_folder, intf,
&rt2x00debug_fop_dev_flags);
if (IS_ERR(intf->dev_flags))
@@ -532,7 +529,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
({ \
(__intf)->__name##_off_entry = \
debugfs_create_u32(__stringify(__name) "_offset", \
- S_IRUGO | S_IWUSR, \
+ S_IRUSR | S_IWUSR, \
(__intf)->register_folder, \
&(__intf)->offset_##__name); \
if (IS_ERR((__intf)->__name##_off_entry)) \
@@ -540,7 +537,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
\
(__intf)->__name##_val_entry = \
debugfs_create_file(__stringify(__name) "_value", \
- S_IRUGO | S_IWUSR, \
+ S_IRUSR | S_IWUSR, \
(__intf)->register_folder, \
(__intf), &rt2x00debug_fop_##__name);\
if (IS_ERR((__intf)->__name##_val_entry)) \
@@ -560,7 +557,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
goto exit;
intf->queue_frame_dump_entry =
- debugfs_create_file("dump", S_IRUGO, intf->queue_folder,
+ debugfs_create_file("dump", S_IRUSR, intf->queue_folder,
intf, &rt2x00debug_fop_queue_dump);
if (IS_ERR(intf->queue_frame_dump_entry))
goto exit;
@@ -569,7 +566,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
init_waitqueue_head(&intf->frame_dump_waitqueue);
intf->queue_stats_entry =
- debugfs_create_file("queue", S_IRUGO, intf->queue_folder,
+ debugfs_create_file("queue", S_IRUSR, intf->queue_folder,
intf, &rt2x00debug_fop_queue_stats);
return;
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 8c93eb8353b..f42283ad7b0 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -1013,6 +1013,7 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
rt2x00dev->intf_associated = 0;
__set_bit(DEVICE_STARTED, &rt2x00dev->flags);
+ __set_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags);
return 0;
}
@@ -1237,9 +1238,9 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
/*
* Reconfigure device.
*/
- rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, 1);
- if (!rt2x00dev->hw->conf.radio_enabled)
- rt2x00lib_disable_radio(rt2x00dev);
+ retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf);
+ if (retval)
+ goto exit;
/*
* Iterator over each active interface to
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index f2c9b0e79b5..c5fb3a72cf3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -125,13 +125,6 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
- * rt2x00queue_free_skb - free a skb
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @skb: The skb to free.
- */
-void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
-
-/**
* rt2x00queue_write_tx_frame - Write TX frame to hardware
* @queue: Queue over which the frame should be send
* @skb: The skb to send
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index f1dcbaa80c3..d0650738863 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -63,7 +63,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
*/
memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
rts_info = IEEE80211_SKB_CB(skb);
- rts_info->flags |= IEEE80211_TX_CTL_DO_NOT_ENCRYPT;
+ rts_info->control.hw_key = NULL;
rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS;
rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
@@ -83,6 +83,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
(struct ieee80211_rts *)(skb->data));
if (rt2x00queue_write_tx_frame(queue, skb)) {
+ dev_kfree_skb_any(skb);
WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
return NETDEV_TX_BUSY;
}
@@ -96,7 +97,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
enum data_queue_qid qid = skb_get_queue_mapping(skb);
- struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct data_queue *queue;
u16 frame_control;
@@ -152,18 +152,6 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
}
}
- /*
- * XXX: This is as wrong as the old mac80211 code was,
- * due to beacons not getting sequence numbers assigned
- * properly.
- */
- if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
- if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
- intf->seqno += 0x10;
- ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
- ieee80211hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
- }
-
if (rt2x00queue_write_tx_frame(queue, skb)) {
ieee80211_stop_queue(rt2x00dev->hw, qid);
return NETDEV_TX_BUSY;
@@ -215,23 +203,43 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
return -ENODEV;
- /*
- * We don't support mixed combinations of sta and ap virtual
- * interfaces. We can only add this interface when the rival
- * interface count is 0.
- */
- if ((conf->type == IEEE80211_IF_TYPE_AP && rt2x00dev->intf_sta_count) ||
- (conf->type != IEEE80211_IF_TYPE_AP && rt2x00dev->intf_ap_count))
- return -ENOBUFS;
-
- /*
- * Check if we exceeded the maximum amount of supported interfaces.
- */
- if ((conf->type == IEEE80211_IF_TYPE_AP &&
- rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf) ||
- (conf->type != IEEE80211_IF_TYPE_AP &&
- rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf))
- return -ENOBUFS;
+ switch (conf->type) {
+ case IEEE80211_IF_TYPE_AP:
+ /*
+ * We don't support mixed combinations of
+ * sta and ap interfaces.
+ */
+ if (rt2x00dev->intf_sta_count)
+ return -ENOBUFS;
+
+ /*
+ * Check if we exceeded the maximum amount
+ * of supported interfaces.
+ */
+ if (rt2x00dev->intf_ap_count >= rt2x00dev->ops->max_ap_intf)
+ return -ENOBUFS;
+
+ break;
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ /*
+ * We don't support mixed combinations of
+ * sta and ap interfaces.
+ */
+ if (rt2x00dev->intf_ap_count)
+ return -ENOBUFS;
+
+ /*
+ * Check if we exceeded the maximum amount
+ * of supported interfaces.
+ */
+ if (rt2x00dev->intf_sta_count >= rt2x00dev->ops->max_sta_intf)
+ return -ENOBUFS;
+
+ break;
+ default:
+ return -EINVAL;
+ }
/*
* Loop through all beacon queues to find a free
@@ -259,6 +267,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
rt2x00dev->intf_sta_count++;
spin_lock_init(&intf->lock);
+ spin_lock_init(&intf->seqlock);
intf->beacon = entry;
if (conf->type == IEEE80211_IF_TYPE_AP)
@@ -322,6 +331,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
+ int force_reconfig;
/*
* Mac80211 might be calling this function while we are trying
@@ -341,7 +351,17 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
}
- rt2x00lib_config(rt2x00dev, conf, 0);
+ /*
+ * When the DEVICE_DIRTY_CONFIG flag is set, the device has recently
+ * been started and the configuration must be forced upon the hardware.
+ * Otherwise registers will not be intialized correctly and could
+ * result in non-working hardware because essential registers aren't
+ * initialized.
+ */
+ force_reconfig =
+ __test_and_clear_bit(DEVICE_DIRTY_CONFIG, &rt2x00dev->flags);
+
+ rt2x00lib_config(rt2x00dev, conf, force_reconfig);
/*
* Reenable RX only if the radio should be on.
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 7f442030f5a..898cdd7f57d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -120,6 +120,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+ struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
struct ieee80211_rate *rate =
ieee80211_get_tx_rate(rt2x00dev->hw, tx_info);
@@ -127,6 +128,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
unsigned int data_length;
unsigned int duration;
unsigned int residual;
+ unsigned long irqflags;
memset(txdesc, 0, sizeof(*txdesc));
@@ -200,6 +202,31 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
}
/*
+ * Hardware should insert sequence counter.
+ * FIXME: We insert a software sequence counter first for
+ * hardware that doesn't support hardware sequence counting.
+ *
+ * This is wrong because beacons are not getting sequence
+ * numbers assigned properly.
+ *
+ * A secondary problem exists for drivers that cannot toggle
+ * sequence counting per-frame, since those will override the
+ * sequence counter given by mac80211.
+ */
+ if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ spin_lock_irqsave(&intf->seqlock, irqflags);
+
+ if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
+ intf->seqno += 0x10;
+ hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
+
+ spin_unlock_irqrestore(&intf->seqlock, irqflags);
+
+ __set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
+ }
+
+ /*
* PLCP setup
* Length calculation depends on OFDM/CCK rate.
*/
@@ -466,9 +493,12 @@ void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev)
if (!rt2x00dev->ops->lib->init_rxentry)
return;
- for (i = 0; i < queue->limit; i++)
+ for (i = 0; i < queue->limit; i++) {
+ queue->entries[i].flags = 0;
+
rt2x00dev->ops->lib->init_rxentry(rt2x00dev,
&queue->entries[i]);
+ }
}
void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev)
@@ -482,9 +512,12 @@ void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev)
if (!rt2x00dev->ops->lib->init_txentry)
continue;
- for (i = 0; i < queue->limit; i++)
+ for (i = 0; i < queue->limit; i++) {
+ queue->entries[i].flags = 0;
+
rt2x00dev->ops->lib->init_txentry(rt2x00dev,
&queue->entries[i]);
+ }
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 8945945c892..ff78e52ce43 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -173,10 +173,10 @@ struct rxdone_entry_desc {
* frame transmission failed due to excessive retries.
*/
enum txdone_entry_desc_flags {
- TXDONE_UNKNOWN = 1 << 0,
- TXDONE_SUCCESS = 1 << 1,
- TXDONE_FAILURE = 1 << 2,
- TXDONE_EXCESSIVE_RETRY = 1 << 3,
+ TXDONE_UNKNOWN,
+ TXDONE_SUCCESS,
+ TXDONE_FAILURE,
+ TXDONE_EXCESSIVE_RETRY,
};
/**
@@ -199,6 +199,7 @@ struct txdone_entry_desc {
* @ENTRY_TXD_RTS_FRAME: This frame is a RTS frame.
* @ENTRY_TXD_CTS_FRAME: This frame is a CTS-to-self frame.
* @ENTRY_TXD_OFDM_RATE: This frame is send out with an OFDM rate.
+ * @ENTRY_TXD_GENERATE_SEQ: This frame requires sequence counter.
* @ENTRY_TXD_FIRST_FRAGMENT: This is the first frame.
* @ENTRY_TXD_MORE_FRAG: This frame is followed by another fragment.
* @ENTRY_TXD_REQ_TIMESTAMP: Require timestamp to be inserted.
@@ -210,6 +211,7 @@ enum txentry_desc_flags {
ENTRY_TXD_RTS_FRAME,
ENTRY_TXD_CTS_FRAME,
ENTRY_TXD_OFDM_RATE,
+ ENTRY_TXD_GENERATE_SEQ,
ENTRY_TXD_FIRST_FRAGMENT,
ENTRY_TXD_MORE_FRAG,
ENTRY_TXD_REQ_TIMESTAMP,
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index 7e88ce5651b..2ea7866abd5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -136,7 +136,7 @@ struct rt2x00_field32 {
*/
#define is_power_of_two(x) ( !((x) & ((x)-1)) )
#define low_bit_mask(x) ( ((x)-1) & ~(x) )
-#define is_valid_mask(x) is_power_of_two(1 + (x) + low_bit_mask(x))
+#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x))
/*
* Macro's to find first set bit in a variable.
@@ -173,8 +173,7 @@ struct rt2x00_field32 {
* does not exceed the given typelimit.
*/
#define FIELD_CHECK(__mask, __type) \
- BUILD_BUG_ON(!__builtin_constant_p(__mask) || \
- !(__mask) || \
+ BUILD_BUG_ON(!(__mask) || \
!is_valid_mask(__mask) || \
(__mask) != (__type)(__mask)) \
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 83862e7f7ae..2050227ea53 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -122,6 +122,38 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
+int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
+ const u8 request, const u8 requesttype,
+ const u16 offset, const void *buffer,
+ const u16 buffer_length,
+ const int timeout)
+{
+ int status = 0;
+ unsigned char *tb;
+ u16 off, len, bsize;
+
+ mutex_lock(&rt2x00dev->usb_cache_mutex);
+
+ tb = (char *)buffer;
+ off = offset;
+ len = buffer_length;
+ while (len && !status) {
+ bsize = min_t(u16, CSR_CACHE_SIZE, len);
+ status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
+ requesttype, off, tb,
+ bsize, timeout);
+
+ tb += bsize;
+ len -= bsize;
+ off += bsize;
+ }
+
+ mutex_unlock(&rt2x00dev->usb_cache_mutex);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff);
+
/*
* TX data handlers.
*/
@@ -149,6 +181,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
* (Only indirectly by looking at the failed TX counters
* in the register).
*/
+ txdesc.flags = 0;
if (!urb->status)
__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
else
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index aad794adf52..3b4a67417f9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -70,8 +70,7 @@
/*
* Cache size
*/
-#define CSR_CACHE_SIZE 8
-#define CSR_CACHE_SIZE_FIRMWARE 64
+#define CSR_CACHE_SIZE 64
/*
* USB request types.
@@ -172,6 +171,25 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
const u16 buffer_length, const int timeout);
/**
+ * rt2x00usb_vendor_request_large_buff - Send register command to device (buffered)
+ * @rt2x00dev: Pointer to &struct rt2x00_dev
+ * @request: USB vendor command (See &enum rt2x00usb_vendor_request)
+ * @requesttype: Request type &USB_VENDOR_REQUEST_*
+ * @offset: Register start offset to perform action on
+ * @buffer: Buffer where information will be read/written to by device
+ * @buffer_length: Size of &buffer
+ * @timeout: Operation timeout
+ *
+ * This function is used to transfer register data in blocks larger
+ * then CSR_CACHE_SIZE. Use for firmware upload, keys and beacons.
+ */
+int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
+ const u8 request, const u8 requesttype,
+ const u16 offset, const void *buffer,
+ const u16 buffer_length,
+ const int timeout);
+
+/**
* rt2x00usb_vendor_request_sw - Send single register command to device
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index f7c1f92c144..087e90b328c 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1004,6 +1004,11 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data,
}
/*
+ * Hardware needs another millisecond before it is ready.
+ */
+ msleep(1);
+
+ /*
* Reset MAC and BBP registers.
*/
reg = 0;
@@ -1544,7 +1549,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
- rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+ rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
+ test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
rt2x00_desc_write(txd, 1, word);
@@ -2278,7 +2284,6 @@ static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
* Initialize all hw fields.
*/
rt2x00dev->hw->flags =
- IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = 0;
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index d383735ab8f..9761eaaa08b 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -890,9 +890,6 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data,
unsigned int i;
int status;
u32 reg;
- const char *ptr = data;
- char *cache;
- int buflen;
/*
* Wait for stable hardware.
@@ -911,31 +908,12 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data,
/*
* Write firmware to device.
- * We setup a seperate cache for this action,
- * since we are going to write larger chunks of data
- * then normally used cache size.
*/
- cache = kmalloc(CSR_CACHE_SIZE_FIRMWARE, GFP_KERNEL);
- if (!cache) {
- ERROR(rt2x00dev, "Failed to allocate firmware cache.\n");
- return -ENOMEM;
- }
-
- for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) {
- buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE);
-
- memcpy(cache, ptr, buflen);
-
- rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT,
- FIRMWARE_IMAGE_BASE + i, 0,
- cache, buflen,
- REGISTER_TIMEOUT32(buflen));
-
- ptr += buflen;
- }
-
- kfree(cache);
+ rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT,
+ FIRMWARE_IMAGE_BASE,
+ data, len,
+ REGISTER_TIMEOUT32(len));
/*
* Send firmware request to device to load firmware,
@@ -1303,7 +1281,8 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min);
rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max);
rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
- rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+ rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE,
+ test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
rt2x00_desc_write(txd, 1, word);
rt2x00_desc_read(txd, 2, &word);
@@ -1352,6 +1331,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
unsigned int beacon_base;
u32 reg;
+ u32 word, len;
/*
* Add the descriptor in front of the skb.
@@ -1361,6 +1341,17 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
skbdesc->desc = entry->skb->data;
/*
+ * Adjust the beacon databyte count. The current number is
+ * calculated before this function gets called, but falsely
+ * assumes that the descriptor was already present in the SKB.
+ */
+ rt2x00_desc_read(skbdesc->desc, 0, &word);
+ len = rt2x00_get_field32(word, TXD_W0_DATABYTE_COUNT);
+ len += skbdesc->desc_len;
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, len);
+ rt2x00_desc_write(skbdesc->desc, 0, word);
+
+ /*
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
*/
@@ -1374,10 +1365,10 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
* Write entire beacon with descriptor to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, beacon_base, 0,
- entry->skb->data, entry->skb->len,
- REGISTER_TIMEOUT32(entry->skb->len));
+ rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, beacon_base,
+ entry->skb->data, entry->skb->len,
+ REGISTER_TIMEOUT32(entry->skb->len));
/*
* Clean up the beacon skb.
@@ -1871,7 +1862,6 @@ static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
* Initialize all hw fields.
*/
rt2x00dev->hw->flags =
- IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM;
rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h
index 3afb49f8866..5a9515c9996 100644
--- a/drivers/net/wireless/rtl8187.h
+++ b/drivers/net/wireless/rtl8187.h
@@ -47,11 +47,13 @@ struct rtl8187_rx_hdr {
struct rtl8187b_rx_hdr {
__le32 flags;
__le64 mac_time;
- u8 noise;
- u8 signal;
+ u8 sq;
+ u8 rssi;
u8 agc;
- u8 reserved;
- __le32 unused;
+ u8 flags2;
+ __le16 snr_long2end;
+ s8 pwdb_g12;
+ u8 fot;
} __attribute__((packed));
/* {rtl8187,rtl8187b}_tx_info is in skb */
@@ -92,6 +94,10 @@ struct rtl8187_priv {
const struct rtl818x_rf_ops *rf;
struct ieee80211_vif *vif;
int mode;
+ /* The mutex protects the TX loopback state.
+ * Any attempt to set channels concurrently locks the device.
+ */
+ struct mutex conf_mutex;
/* rtl8187 specific */
struct ieee80211_channel channels[14];
@@ -100,6 +106,7 @@ struct rtl8187_priv {
struct usb_device *udev;
u32 rx_conf;
u16 txpwr_base;
+ u16 seqno;
u8 asic_rev;
u8 is_rtl8187b;
enum {
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index d3067b1216c..ca5deb6244e 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -31,6 +31,8 @@ MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver");
MODULE_LICENSE("GPL");
static struct usb_device_id rtl8187_table[] __devinitdata = {
+ /* Asus */
+ {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187},
/* Realtek */
{USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187},
{USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B},
@@ -38,6 +40,7 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
/* Netgear */
{USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187},
{USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187},
+ {USB_DEVICE(0x0846, 0x4260), .driver_info = DEVICE_RTL8187B},
/* HP */
{USB_DEVICE(0x03f0, 0xca02), .driver_info = DEVICE_RTL8187},
/* Sitecom */
@@ -169,6 +172,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct rtl8187_priv *priv = dev->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
unsigned int ep;
void *buf;
struct urb *urb;
@@ -234,6 +238,20 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
ep = epmap[skb_get_queue_mapping(skb)];
}
+ /* FIXME: The sequence that follows is needed for this driver to
+ * work with mac80211 since "mac80211: fix TX sequence numbers".
+ * As with the temporary code in rt2x00, changes will be needed
+ * to get proper sequence numbers on beacons. In addition, this
+ * patch places the sequence number in the hardware state, which
+ * limits us to a single virtual state.
+ */
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+ if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+ priv->seqno += 0x10;
+ ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+ ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
+ }
+
info->driver_data[0] = dev;
info->driver_data[1] = urb;
@@ -257,6 +275,7 @@ static void rtl8187_rx_cb(struct urb *urb)
struct ieee80211_rx_status rx_status = { 0 };
int rate, signal;
u32 flags;
+ u32 quality;
spin_lock(&priv->rx_queue.lock);
if (skb->next)
@@ -280,44 +299,57 @@ static void rtl8187_rx_cb(struct urb *urb)
flags = le32_to_cpu(hdr->flags);
signal = hdr->signal & 0x7f;
rx_status.antenna = (hdr->signal >> 7) & 1;
- rx_status.signal = signal;
rx_status.noise = hdr->noise;
rx_status.mactime = le64_to_cpu(hdr->mac_time);
- priv->signal = signal;
priv->quality = signal;
+ rx_status.qual = priv->quality;
priv->noise = hdr->noise;
+ rate = (flags >> 20) & 0xF;
+ if (rate > 3) { /* OFDM rate */
+ if (signal > 90)
+ signal = 90;
+ else if (signal < 25)
+ signal = 25;
+ signal = 90 - signal;
+ } else { /* CCK rate */
+ if (signal > 95)
+ signal = 95;
+ else if (signal < 30)
+ signal = 30;
+ signal = 95 - signal;
+ }
+ rx_status.signal = signal;
+ priv->signal = signal;
} else {
struct rtl8187b_rx_hdr *hdr =
(typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr));
+ /* The Realtek datasheet for the RTL8187B shows that the RX
+ * header contains the following quantities: signal quality,
+ * RSSI, AGC, the received power in dB, and the measured SNR.
+ * In testing, none of these quantities show qualitative
+ * agreement with AP signal strength, except for the AGC,
+ * which is inversely proportional to the strength of the
+ * signal. In the following, the quality and signal strength
+ * are derived from the AGC. The arbitrary scaling constants
+ * are chosen to make the results close to the values obtained
+ * for a BCM4312 using b43 as the driver. The noise is ignored
+ * for now.
+ */
flags = le32_to_cpu(hdr->flags);
- signal = hdr->agc >> 1;
- rx_status.antenna = (hdr->signal >> 7) & 1;
- rx_status.signal = 64 - min(hdr->noise, (u8)64);
- rx_status.noise = hdr->noise;
+ quality = 170 - hdr->agc;
+ if (quality > 100)
+ quality = 100;
+ signal = 14 - hdr->agc / 2;
+ rx_status.qual = quality;
+ priv->quality = quality;
+ rx_status.signal = signal;
+ priv->signal = signal;
+ rx_status.antenna = (hdr->rssi >> 7) & 1;
rx_status.mactime = le64_to_cpu(hdr->mac_time);
- priv->signal = hdr->signal;
- priv->quality = hdr->agc >> 1;
- priv->noise = hdr->noise;
+ rate = (flags >> 20) & 0xF;
}
skb_trim(skb, flags & 0x0FFF);
- rate = (flags >> 20) & 0xF;
- if (rate > 3) { /* OFDM rate */
- if (signal > 90)
- signal = 90;
- else if (signal < 25)
- signal = 25;
- signal = 90 - signal;
- } else { /* CCK rate */
- if (signal > 95)
- signal = 95;
- else if (signal < 30)
- signal = 30;
- signal = 95 - signal;
- }
-
- rx_status.qual = priv->quality;
- rx_status.signal = signal;
rx_status.rate_idx = rate;
rx_status.freq = dev->conf.channel->center_freq;
rx_status.band = dev->conf.channel->band;
@@ -697,6 +729,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
if (ret)
return ret;
+ mutex_lock(&priv->conf_mutex);
if (priv->is_rtl8187b) {
reg = RTL818X_RX_CONF_MGMT |
RTL818X_RX_CONF_DATA |
@@ -718,6 +751,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
(7 << 0 /* long retry limit */) |
(7 << 21 /* MAX TX DMA */));
rtl8187_init_urbs(dev);
+ mutex_unlock(&priv->conf_mutex);
return 0;
}
@@ -761,6 +795,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
reg |= RTL818X_CMD_TX_ENABLE;
reg |= RTL818X_CMD_RX_ENABLE;
rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+ mutex_unlock(&priv->conf_mutex);
return 0;
}
@@ -772,6 +807,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
struct sk_buff *skb;
u32 reg;
+ mutex_lock(&priv->conf_mutex);
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
reg = rtl818x_ioread8(priv, &priv->map->CMD);
@@ -791,7 +827,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
usb_kill_urb(info->urb);
kfree_skb(skb);
}
- return;
+ mutex_unlock(&priv->conf_mutex);
}
static int rtl8187_add_interface(struct ieee80211_hw *dev,
@@ -811,6 +847,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
return -EOPNOTSUPP;
}
+ mutex_lock(&priv->conf_mutex);
priv->vif = conf->vif;
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
@@ -819,6 +856,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
((u8 *)conf->mac_addr)[i]);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+ mutex_unlock(&priv->conf_mutex);
return 0;
}
@@ -826,8 +864,10 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct rtl8187_priv *priv = dev->priv;
+ mutex_lock(&priv->conf_mutex);
priv->mode = IEEE80211_IF_TYPE_MNTR;
priv->vif = NULL;
+ mutex_unlock(&priv->conf_mutex);
}
static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -835,6 +875,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
struct rtl8187_priv *priv = dev->priv;
u32 reg;
+ mutex_lock(&priv->conf_mutex);
reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
/* Enable TX loopback on MAC level to avoid TX during channel
* changes, as this has be seen to causes problems and the
@@ -867,6 +908,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100);
+ mutex_unlock(&priv->conf_mutex);
return 0;
}
@@ -878,6 +920,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
int i;
u8 reg;
+ mutex_lock(&priv->conf_mutex);
for (i = 0; i < ETH_ALEN; i++)
rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
@@ -891,6 +934,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
rtl818x_iowrite8(priv, &priv->map->MSR, reg);
}
+ mutex_unlock(&priv->conf_mutex);
return 0;
}
@@ -1015,9 +1059,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
priv->mode = IEEE80211_IF_TYPE_MNTR;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_UNSPEC;
- dev->max_signal = 65;
+ IEEE80211_HW_RX_INCLUDES_FCS;
eeprom.data = dev;
eeprom.register_read = rtl8187_eeprom_register_read;
@@ -1132,10 +1174,16 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
(*channel++).hw_value = txpwr >> 8;
}
- if (priv->is_rtl8187b)
+ if (priv->is_rtl8187b) {
printk(KERN_WARNING "rtl8187: 8187B chip detected. Support "
"is EXPERIMENTAL, and could damage your\n"
" hardware, use at your own risk\n");
+ dev->flags |= IEEE80211_HW_SIGNAL_DBM;
+ } else {
+ dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC;
+ dev->max_signal = 65;
+ }
+
if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b)
printk(KERN_INFO "rtl8187: inconsistency between id with OEM"
" info!\n");
@@ -1154,6 +1202,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
printk(KERN_ERR "rtl8187: Cannot register device\n");
goto err_free_dev;
}
+ mutex_init(&priv->conf_mutex);
printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n",
wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 49ae9700395..136220b5ca8 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -1409,9 +1409,6 @@ static void wavelan_set_multicast_list(struct net_device * dev)
lp->mc_count = 0;
wv_82586_reconfig(dev);
-
- /* Tell the kernel that we are doing a really bad job. */
- dev->flags |= IFF_PROMISC;
}
} else
/* Are there multicast addresses to send? */
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index b584c0ecc62..00a3559e5aa 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -1412,9 +1412,6 @@ wavelan_set_multicast_list(struct net_device * dev)
lp->mc_count = 0;
wv_82593_reconfig(dev);
-
- /* Tell the kernel that we are doing a really bad job... */
- dev->flags |= IFF_PROMISC;
}
}
else
@@ -1433,9 +1430,6 @@ wavelan_set_multicast_list(struct net_device * dev)
lp->mc_count = 0;
wv_82593_reconfig(dev);
-
- /* Tell the kernel that we are doing a really bad job... */
- dev->flags |= IFF_ALLMULTI;
}
}
else
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index fcc532bb6a7..4d7b98b0503 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -935,7 +935,6 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band;
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
IEEE80211_HW_SIGNAL_DB;
hw->max_signal = 100;