aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h1
-rw-r--r--drivers/net/wireless/ath/ar9170/mac.c24
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c20
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h4
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c21
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c121
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c29
-rw-r--r--drivers/net/wireless/ath/ath5k/led.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile3
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h5
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c319
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.h98
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c35
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c239
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h58
-rw-r--r--drivers/net/wireless/ath/ath9k/initvals.h10
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c40
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h64
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c9
24 files changed, 971 insertions, 167 deletions
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index ce407248d7d..914e4718a9a 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -178,6 +178,7 @@ struct ar9170 {
/* beaconing */
struct sk_buff *beacon;
struct work_struct beacon_work;
+ bool enable_beacon;
/* cryptographic engine */
u64 usedkeys;
diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c
index 60049366e86..614e3218a2b 100644
--- a/drivers/net/wireless/ath/ar9170/mac.c
+++ b/drivers/net/wireless/ath/ar9170/mac.c
@@ -383,24 +383,26 @@ int ar9170_set_beacon_timers(struct ar9170 *ar)
if (ar->vif) {
v |= ar->vif->bss_conf.beacon_int;
- switch (ar->vif->type) {
- case NL80211_IFTYPE_MESH_POINT:
- case NL80211_IFTYPE_ADHOC:
- v |= BIT(25);
- break;
- case NL80211_IFTYPE_AP:
- v |= BIT(24);
- pretbtt = (ar->vif->bss_conf.beacon_int - 6) << 16;
- break;
- default:
+ if (ar->enable_beacon) {
+ switch (ar->vif->type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_ADHOC:
+ v |= BIT(25);
+ break;
+ case NL80211_IFTYPE_AP:
+ v |= BIT(24);
+ pretbtt = (ar->vif->bss_conf.beacon_int - 6) <<
+ 16;
+ break;
+ default:
break;
+ }
}
v |= ar->vif->bss_conf.dtim_period << 16;
}
ar9170_regwrite_begin(ar);
-
ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt);
ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v);
ar9170_regwrite_finish();
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 658b32312ca..c1f8c69db16 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -2031,12 +2031,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
goto out;
}
- if (changed & BSS_CHANGED_BEACON_INT) {
- err = ar9170_set_beacon_timers(ar);
- if (err)
- goto out;
- }
-
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
/* adjust slot time for 5 GHz */
@@ -2148,11 +2142,17 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
goto out;
}
- if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) {
+ if (changed & BSS_CHANGED_BEACON_ENABLED)
+ ar->enable_beacon = bss_conf->enable_beacon;
+
+ if (changed & BSS_CHANGED_BEACON) {
err = ar9170_update_beacon(ar);
if (err)
goto out;
+ }
+ if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_INT)) {
err = ar9170_set_beacon_timers(ar);
if (err)
goto out;
@@ -2165,12 +2165,6 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
#endif /* CONFIG_AR9170_LEDS */
}
- if (changed & BSS_CHANGED_BEACON_INT) {
- err = ar9170_set_beacon_timers(ar);
- if (err)
- goto out;
- }
-
if (changed & BSS_CHANGED_HT) {
/* TODO */
err = 0;
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 862762cea54..6cd5efcec41 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -306,6 +306,7 @@ struct ath5k_srev_name {
#define AR5K_SREV_AR5311B 0x30 /* Spirit */
#define AR5K_SREV_AR5211 0x40 /* Oahu */
#define AR5K_SREV_AR5212 0x50 /* Venice */
+#define AR5K_SREV_AR5212_V4 0x54 /* ??? */
#define AR5K_SREV_AR5213 0x55 /* ??? */
#define AR5K_SREV_AR5213A 0x59 /* Hainan */
#define AR5K_SREV_AR2413 0x78 /* Griffin lite */
@@ -1037,6 +1038,7 @@ struct ath5k_hw {
bool ah_turbo;
bool ah_calibration;
bool ah_single_chip;
+ bool ah_aes_support;
bool ah_combined_mic;
enum ath5k_version ah_version;
@@ -1158,7 +1160,7 @@ struct ath5k_hw {
*/
/* Attach/Detach Functions */
-extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version);
+extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc);
extern void ath5k_hw_detach(struct ath5k_hw *ah);
/* LED functions */
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 65d438b59f6..71a1bd25451 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -95,17 +95,17 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
* ath5k_hw_attach - Check if hw is supported and init the needed structs
*
* @sc: The &struct ath5k_softc we got from the driver's attach function
- * @mac_version: The mac version id (check out ath5k.h) based on pci id
*
* Check if the device is supported, perform a POST and initialize the needed
* structs. Returns -ENOMEM if we don't have memory for the needed structs,
* -ENODEV if the device is not supported or prints an error msg if something
* else went wrong.
*/
-struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
+struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc)
{
struct ath5k_hw *ah;
struct pci_dev *pdev = sc->pdev;
+ struct ath5k_eeprom_info *ee;
int ret;
u32 srev;
@@ -135,9 +135,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
ah->ah_software_retry = false;
/*
- * Set the mac version based on the pci id
+ * Find the mac version
*/
- ah->ah_version = mac_version;
+ srev = ath5k_hw_reg_read(ah, AR5K_SREV);
+ if (srev < AR5K_SREV_AR5311)
+ ah->ah_version = AR5K_AR5210;
+ else if (srev < AR5K_SREV_AR5212)
+ ah->ah_version = AR5K_AR5211;
+ else
+ ah->ah_version = AR5K_AR5212;
/*Fill the ath5k_hw struct with the needed functions*/
ret = ath5k_hw_init_desc_functions(ah);
@@ -150,7 +156,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
goto err_free;
/* Get MAC, PHY and RADIO revisions */
- srev = ath5k_hw_reg_read(ah, AR5K_SREV);
ah->ah_mac_srev = srev;
ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
@@ -315,6 +320,12 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
goto err_free;
}
+ /* Crypto settings */
+ ee = &ah->ah_capabilities.cap_eeprom;
+ ah->ah_aes_support = srev >= AR5K_SREV_AR5212_V4 &&
+ (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
+ !AR5K_EEPROM_AES_DIS(ee->ee_misc5));
+
if (srev >= AR5K_SREV_AR2414) {
ah->ah_combined_mic = true;
AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE,
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 5056410d788..9c6ab5378f6 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -84,24 +84,24 @@ MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
/* Known PCI ids */
static const struct pci_device_id ath5k_pci_id_table[] = {
- { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */
- { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */
- { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/
- { PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */
- { PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */
- { PCI_VDEVICE(3COM_2, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */
- { PCI_VDEVICE(3COM, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */
- { PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */
- { PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */
- { 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 }, /* PCI-E cards */
- { PCI_VDEVICE(ATHEROS, 0x001d), .driver_data = AR5K_AR5212 }, /* 2417 Nala */
+ { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */
+ { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */
+ { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/
+ { PCI_VDEVICE(ATHEROS, 0x0012) }, /* 5211 */
+ { PCI_VDEVICE(ATHEROS, 0x0013) }, /* 5212 */
+ { PCI_VDEVICE(3COM_2, 0x0013) }, /* 3com 5212 */
+ { PCI_VDEVICE(3COM, 0x0013) }, /* 3com 3CRDAG675 5212 */
+ { PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */
+ { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */
+ { PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */
+ { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
+ { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
+ { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
{ 0 }
};
MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
@@ -566,7 +566,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
}
/* Initialize device */
- sc->ah = ath5k_hw_attach(sc, id->driver_data);
+ sc->ah = ath5k_hw_attach(sc);
if (IS_ERR(sc->ah)) {
ret = PTR_ERR(sc->ah);
goto err_irq;
@@ -1741,7 +1741,7 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
static void
ath5k_tasklet_rx(unsigned long data)
{
- struct ieee80211_rx_status rxs = {};
+ struct ieee80211_rx_status *rxs;
struct ath5k_rx_status rs = {};
struct sk_buff *skb, *next_skb;
dma_addr_t next_skb_addr;
@@ -1751,6 +1751,7 @@ ath5k_tasklet_rx(unsigned long data)
int ret;
int hdrlen;
int padsize;
+ int rx_flag;
spin_lock(&sc->rxbuflock);
if (list_empty(&sc->rxbuf)) {
@@ -1758,7 +1759,7 @@ ath5k_tasklet_rx(unsigned long data)
goto unlock;
}
do {
- rxs.flag = 0;
+ rx_flag = 0;
bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
BUG_ON(bf->skb == NULL);
@@ -1802,7 +1803,7 @@ ath5k_tasklet_rx(unsigned long data)
goto accept;
}
if (rs.rs_status & AR5K_RXERR_MIC) {
- rxs.flag |= RX_FLAG_MMIC_ERROR;
+ rx_flag |= RX_FLAG_MMIC_ERROR;
goto accept;
}
@@ -1840,6 +1841,7 @@ accept:
memmove(skb->data + padsize, skb->data, hdrlen);
skb_pull(skb, padsize);
}
+ rxs = IEEE80211_SKB_RXCB(skb);
/*
* always extend the mac timestamp, since this information is
@@ -1861,41 +1863,40 @@ accept:
* impossible to comply to that. This affects IBSS merge only
* right now, so it's not too bad...
*/
- rxs.mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
- rxs.flag |= RX_FLAG_TSFT;
+ rxs->mactime = ath5k_extend_tsf(sc->ah, rs.rs_tstamp);
+ rxs->flag = rx_flag | RX_FLAG_TSFT;
- rxs.freq = sc->curchan->center_freq;
- rxs.band = sc->curband->band;
+ rxs->freq = sc->curchan->center_freq;
+ rxs->band = sc->curband->band;
- rxs.noise = sc->ah->ah_noise_floor;
- rxs.signal = rxs.noise + rs.rs_rssi;
+ rxs->noise = sc->ah->ah_noise_floor;
+ rxs->signal = rxs->noise + rs.rs_rssi;
/* An rssi of 35 indicates you should be able use
* 54 Mbps reliably. A more elaborate scheme can be used
* here but it requires a map of SNR/throughput for each
* possible mode used */
- rxs.qual = rs.rs_rssi * 100 / 35;
+ rxs->qual = rs.rs_rssi * 100 / 35;
/* rssi can be more than 35 though, anything above that
* should be considered at 100% */
- if (rxs.qual > 100)
- rxs.qual = 100;
+ if (rxs->qual > 100)
+ rxs->qual = 100;
- rxs.antenna = rs.rs_antenna;
- rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
- rxs.flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
+ rxs->antenna = rs.rs_antenna;
+ rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
+ rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
- if (rxs.rate_idx >= 0 && rs.rs_rate ==
- sc->curband->bitrates[rxs.rate_idx].hw_value_short)
- rxs.flag |= RX_FLAG_SHORTPRE;
+ if (rxs->rate_idx >= 0 && rs.rs_rate ==
+ sc->curband->bitrates[rxs->rate_idx].hw_value_short)
+ rxs->flag |= RX_FLAG_SHORTPRE;
ath5k_debug_dump_skb(sc, skb, "RX ", 0);
/* check beacons in IBSS mode */
if (sc->opmode == NL80211_IFTYPE_ADHOC)
- ath5k_check_ibss_tsf(sc, skb, &rxs);
+ ath5k_check_ibss_tsf(sc, skb, rxs);
- memcpy(IEEE80211_SKB_RXCB(skb), &rxs, sizeof(rxs));
ieee80211_rx(sc->hw, skb);
bf->skb = next_skb;
@@ -2918,6 +2919,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
struct ath5k_hw *ah = sc->ah;
u32 mfilt[2], rfilt;
+ mutex_lock(&sc->lock);
+
mfilt[0] = multicast;
mfilt[1] = multicast >> 32;
@@ -2968,22 +2971,25 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
/* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */
- if (sc->opmode == NL80211_IFTYPE_MONITOR)
- rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
- AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
- if (sc->opmode != NL80211_IFTYPE_STATION)
- rfilt |= AR5K_RX_FILTER_PROBEREQ;
- if (sc->opmode != NL80211_IFTYPE_AP &&
- sc->opmode != NL80211_IFTYPE_MESH_POINT &&
- test_bit(ATH_STAT_PROMISC, sc->status))
- rfilt |= AR5K_RX_FILTER_PROM;
- if ((sc->opmode == NL80211_IFTYPE_STATION && sc->assoc) ||
- sc->opmode == NL80211_IFTYPE_ADHOC ||
- sc->opmode == NL80211_IFTYPE_AP)
- rfilt |= AR5K_RX_FILTER_BEACON;
- if (sc->opmode == NL80211_IFTYPE_MESH_POINT)
- rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON |
- AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM;
+ switch (sc->opmode) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_MONITOR:
+ rfilt |= AR5K_RX_FILTER_CONTROL |
+ AR5K_RX_FILTER_BEACON |
+ AR5K_RX_FILTER_PROBEREQ |
+ AR5K_RX_FILTER_PROM;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_ADHOC:
+ rfilt |= AR5K_RX_FILTER_PROBEREQ |
+ AR5K_RX_FILTER_BEACON;
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (sc->assoc)
+ rfilt |= AR5K_RX_FILTER_BEACON;
+ default:
+ break;
+ }
/* Set filters */
ath5k_hw_set_rx_filter(ah, rfilt);
@@ -2993,6 +2999,8 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
/* Set the cached hw filter flags, this will alter actually
* be set in HW */
sc->filter_flags = rfilt;
+
+ mutex_unlock(&sc->lock);
}
static int
@@ -3014,6 +3022,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
case ALG_TKIP:
break;
case ALG_CCMP:
+ if (sc->ah->ah_aes_support)
+ break;
+
return -EOPNOTSUPP;
default:
WARN_ON(1);
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index 8af477dd6fc..644962adda9 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -414,27 +414,11 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
break;
}
-done:
- /* return new offset */
- *offset = o;
-
- return 0;
-}
-
-/*
- * Read turbo mode information on newer EEPROM versions
- */
-static int
-ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
- u32 *offset, unsigned int mode)
-{
- struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
- u32 o = *offset;
- u16 val;
- int ret;
-
+ /*
+ * Read turbo mode information on newer EEPROM versions
+ */
if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)
- return 0;
+ goto done;
switch (mode){
case AR5K_EEPROM_MODE_11A:
@@ -468,6 +452,7 @@ ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah,
break;
}
+done:
/* return new offset */
*offset = o;
@@ -504,10 +489,6 @@ ath5k_eeprom_init_modes(struct ath5k_hw *ah)
ret = ath5k_eeprom_read_modes(ah, &offset, mode);
if (ret)
return ret;
-
- ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode);
- if (ret)
- return ret;
}
/* override for older eeprom versions for better performance */
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 876725f08b6..b767c3b67b2 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -69,6 +69,8 @@ static const struct pci_device_id ath5k_led_devices[] = {
{ ATH_SDEVICE(PCI_VENDOR_ID_AZWAVE, 0x1026), ATH_LED(3, 0) },
/* IBM ThinkPad AR5BXB6 (legovini@spiro.fisica.unipd.it) */
{ ATH_SDEVICE(PCI_VENDOR_ID_IBM, 0x058a), ATH_LED(1, 0) },
+ /* HP Compaq C700 (nitrousnrg@gmail.com) */
+ { ATH_SDEVICE(PCI_VENDOR_ID_HP, 0x0137b), ATH_LED(3, 1) },
/* IBM-specific AR5212 (all others) */
{ PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) },
{ }
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 28443e05ec1..ff2c9a26c10 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -12,7 +12,8 @@ ath9k-y += hw.o \
recv.o \
xmit.o \
virtual.o \
- rc.o
+ rc.o \
+ btcoex.o
ath9k-$(CONFIG_PCI) += pci.o
ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 7705da1103f..1c68a9da22d 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -26,6 +26,7 @@
#include "rc.h"
#include "debug.h"
#include "../ath.h"
+#include "btcoex.h"
struct ath_node;
@@ -521,6 +522,8 @@ struct ath_led {
#define SC_OP_WAIT_FOR_PSPOLL_DATA BIT(17)
#define SC_OP_WAIT_FOR_TX_ACK BIT(18)
#define SC_OP_BEACON_SYNC BIT(19)
+#define SC_OP_BTCOEX_ENABLED BIT(20)
+#define SC_OP_BT_PRIORITY_DETECTED BIT(21)
struct ath_bus_ops {
void (*read_cachesize)(struct ath_softc *sc, int *csz);
@@ -609,6 +612,7 @@ struct ath_softc {
struct ath_bus_ops *bus_ops;
struct ath_beacon_config cur_beacon_conf;
struct delayed_work tx_complete_work;
+ struct ath_btcoex_info btcoex_info;
};
struct ath_wiphy {
@@ -705,4 +709,5 @@ bool ath9k_all_wiphys_idle(struct ath_softc *sc);
void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val);
unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset);
+int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
#endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
new file mode 100644
index 00000000000..8fb35674882
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2009 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 "ath9k.h"
+
+static const struct ath_btcoex_config ath_bt_config = { 0, true, true,
+ ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true };
+
+
+/*
+ * Detects if there is any priority bt traffic
+ */
+static void ath_detect_bt_priority(struct ath_softc *sc)
+{
+ struct ath_btcoex_info *btinfo = &sc->btcoex_info;
+
+ if (ath9k_hw_gpio_get(sc->sc_ah, btinfo->btpriority_gpio))
+ btinfo->bt_priority_cnt++;
+
+ if (time_after(jiffies, btinfo->bt_priority_time +
+ msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
+ if (btinfo->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
+ DPRINTF(sc, ATH_DBG_BTCOEX,
+ "BT priority traffic detected");
+ sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
+ } else {
+ sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+ }
+
+ btinfo->bt_priority_cnt = 0;
+ btinfo->bt_priority_time = jiffies;
+ }
+}
+
+/*
+ * Configures appropriate weight based on stomp type.
+ */
+static void ath_btcoex_bt_stomp(struct ath_softc *sc,
+ struct ath_btcoex_info *btinfo,
+ int stomp_type)
+{
+
+ switch (stomp_type) {
+ case ATH_BTCOEX_STOMP_ALL:
+ ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
+ AR_STOMP_ALL_WLAN_WGHT);
+ break;
+ case ATH_BTCOEX_STOMP_LOW:
+ ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
+ break;
+ case ATH_BTCOEX_STOMP_NONE:
+ ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
+ AR_STOMP_NONE_WLAN_WGHT);
+ break;
+ default:
+ DPRINTF(sc, ATH_DBG_BTCOEX, "Invalid Stomptype\n");
+ break;
+ }
+
+ ath9k_hw_btcoex_enable(sc->sc_ah);
+}
+
+/*
+ * This is the master bt coex timer which runs for every
+ * 45ms, bt traffic will be given priority during 55% of this
+ * period while wlan gets remaining 45%
+ */
+
+static void ath_btcoex_period_timer(unsigned long data)
+{
+ struct ath_softc *sc = (struct ath_softc *) data;
+ struct ath_btcoex_info *btinfo = &sc->btcoex_info;
+ unsigned long flags;
+
+ ath_detect_bt_priority(sc);
+
+ spin_lock_irqsave(&btinfo->btcoex_lock, flags);
+
+ ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type);
+
+ spin_unlock_irqrestore(&btinfo->btcoex_lock, flags);
+
+ if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) {
+ if (btinfo->hw_timer_enabled)
+ ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+
+ ath_gen_timer_start(sc->sc_ah,
+ btinfo->no_stomp_timer,
+ (ath9k_hw_gettsf32(sc->sc_ah) +
+ btinfo->btcoex_no_stomp),
+ btinfo->btcoex_no_stomp * 10);
+ btinfo->hw_timer_enabled = true;
+ }
+
+ mod_timer(&btinfo->period_timer, jiffies +
+ msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
+}
+
+/*
+ * Generic tsf based hw timer which configures weight
+ * registers to time slice between wlan and bt traffic
+ */
+
+static void ath_btcoex_no_stomp_timer(void *arg)
+{
+ struct ath_softc *sc = (struct ath_softc *)arg;
+ struct ath_btcoex_info *btinfo = &sc->btcoex_info;
+ unsigned long flags;
+
+ DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n");
+
+ spin_lock_irqsave(&btinfo->btcoex_lock, flags);
+
+ if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
+ ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE);
+ else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
+ ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW);
+
+ spin_unlock_irqrestore(&btinfo->btcoex_lock, flags);
+}
+
+static int ath_init_btcoex_info(struct ath_hw *hw,
+ struct ath_btcoex_info *btcoex_info)
+{
+ u32 i;
+ int qnum;
+
+ qnum = ath_tx_get_qnum(hw->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
+
+ btcoex_info->bt_coex_mode =
+ (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) |
+ SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) |
+ SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
+ SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
+ SM(ath_bt_config.bt_mode, AR_BT_MODE) |
+ SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) |
+ SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
+ SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) |
+ SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) |
+ SM(qnum, AR_BT_QCU_THRESH);
+
+ btcoex_info->bt_coex_mode2 =
+ SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
+ SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
+ AR_BT_DISABLE_BT_ANT;
+
+ btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+
+ btcoex_info->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
+
+ btcoex_info->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+ btcoex_info->btcoex_period / 100;
+
+ for (i = 0; i < 32; i++)
+ hw->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i;
+
+ setup_timer(&btcoex_info->period_timer, ath_btcoex_period_timer,
+ (unsigned long) hw->ah_sc);
+
+ btcoex_info->no_stomp_timer = ath_gen_timer_alloc(hw,
+ ath_btcoex_no_stomp_timer,
+ ath_btcoex_no_stomp_timer,
+ (void *)hw->ah_sc, AR_FIRST_NDP_TIMER);
+
+ if (btcoex_info->no_stomp_timer == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&btcoex_info->btcoex_lock);
+
+ return 0;
+}
+
+int ath9k_hw_btcoex_init(struct ath_hw *ah)
+{
+ struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+ int ret = 0;
+
+ if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
+ /* connect bt_active to baseband */
+ REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
+ AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
+
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
+
+ /* Set input mux for bt_active to gpio pin */
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+ btcoex_info->btactive_gpio);
+
+ /* Configure the desired gpio port for input */
+ ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
+ } else {
+ /* btcoex 3-wire */
+ REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+ (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
+ AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
+
+ /* Set input mux for bt_prority_async and
+ * bt_active_async to GPIO pins */
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+ btcoex_info->btactive_gpio);
+
+ REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+ AR_GPIO_INPUT_MUX1_BT_PRIORITY,
+ btcoex_info->btpriority_gpio);
+
+ /* Configure the desired GPIO ports for input */
+
+ ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
+ ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio);
+
+ ret = ath_init_btcoex_info(ah, btcoex_info);
+ }
+
+ return ret;
+}
+
+void ath9k_hw_btcoex_enable(struct ath_hw *ah)
+{
+ struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+
+ if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
+ /* Configure the desired GPIO port for TX_FRAME output */
+ ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
+ } else {
+ /*
+ * Program coex mode and weight registers to
+ * enable coex 3-wire
+ */
+ REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode);
+ REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights);
+ REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2);
+
+ REG_RMW_FIELD(ah, AR_QUIET1,
+ AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
+ REG_RMW_FIELD(ah, AR_PCU_MISC,
+ AR_PCU_BT_ANT_PREVENT_RX, 0);
+
+ ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
+ }
+
+ REG_RMW(ah, AR_GPIO_PDPU,
+ (0x2 << (btcoex_info->btactive_gpio * 2)),
+ (0x3 << (btcoex_info->btactive_gpio * 2)));
+
+ ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED;
+}
+
+void ath9k_hw_btcoex_disable(struct ath_hw *ah)
+{
+ struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+
+ ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0);
+
+ ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+
+ if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) {
+ REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
+ REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
+ REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
+ }
+
+ ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED;
+}
+
+/*
+ * Pause btcoex timer and bt duty cycle timer
+ */
+void ath_btcoex_timer_pause(struct ath_softc *sc,
+ struct ath_btcoex_info *btinfo)
+{
+
+ del_timer_sync(&btinfo->period_timer);
+
+ if (btinfo->hw_timer_enabled)
+ ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+
+ btinfo->hw_timer_enabled = false;
+}
+
+/*
+ * (Re)start btcoex timers
+ */
+void ath_btcoex_timer_resume(struct ath_softc *sc,
+ struct ath_btcoex_info *btinfo)
+{
+
+ DPRINTF(sc, ATH_DBG_BTCOEX, "Starting btcoex timers");
+
+ /* make sure duty cycle timer is also stopped when resuming */
+ if (btinfo->hw_timer_enabled)
+ ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+
+ btinfo->bt_priority_cnt = 0;
+ btinfo->bt_priority_time = jiffies;
+ sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+
+ mod_timer(&btinfo->period_timer, jiffies);
+}
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
new file mode 100644
index 00000000000..45568196c59
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2009 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 BTCOEX_H
+#define BTCOEX_H
+
+#define ATH_WLANACTIVE_GPIO 5
+#define ATH_BTACTIVE_GPIO 6
+
+#define ATH_BTCOEX_DEF_BT_PERIOD 45
+#define ATH_BTCOEX_DEF_DUTY_CYCLE 55
+#define ATH_BTCOEX_BMISS_THRESH 50
+
+#define ATH_BT_PRIORITY_TIME_THRESHOLD 1000 /* ms */
+#define ATH_BT_CNT_THRESHOLD 3
+
+enum ath_btcoex_scheme {
+ ATH_BTCOEX_CFG_NONE,
+ ATH_BTCOEX_CFG_2WIRE,
+ ATH_BTCOEX_CFG_3WIRE,
+};
+
+enum ath_stomp_type {
+ ATH_BTCOEX_NO_STOMP,
+ ATH_BTCOEX_STOMP_ALL,
+ ATH_BTCOEX_STOMP_LOW,
+ ATH_BTCOEX_STOMP_NONE
+};
+
+enum ath_bt_mode {
+ ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */
+ ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */
+ ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */
+ ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */
+};
+
+struct ath_btcoex_config {
+ u8 bt_time_extend;
+ bool bt_txstate_extend;
+ bool bt_txframe_extend;
+ enum ath_bt_mode bt_mode; /* coexistence mode */
+ bool bt_quiet_collision;
+ bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/
+ u8 bt_priority_time;
+ u8 bt_first_slot_time;
+ bool bt_hold_rx_clear;
+};
+
+struct ath_btcoex_info {
+ enum ath_btcoex_scheme btcoex_scheme;
+ u8 wlanactive_gpio;
+ u8 btactive_gpio;
+ u8 btpriority_gpio;
+ u8 bt_duty_cycle; /* BT duty cycle in percentage */
+ int bt_stomp_type; /* Types of BT stomping */
+ u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */
+ u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */
+ u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */
+ u32 btcoex_no_stomp; /* in usec */
+ u32 btcoex_period; /* in usec */
+ u32 bt_priority_cnt;
+ unsigned long bt_priority_time;
+ bool hw_timer_enabled;
+ spinlock_t btcoex_lock;
+ struct timer_list period_timer; /* Timer for BT period */
+ struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/
+};
+
+int ath9k_hw_btcoex_init(struct ath_hw *ah);
+void ath9k_hw_btcoex_enable(struct ath_hw *ah);
+void ath9k_hw_btcoex_disable(struct ath_hw *ah);
+void ath_btcoex_timer_resume(struct ath_softc *sc,
+ struct ath_btcoex_info *btinfo);
+void ath_btcoex_timer_pause(struct ath_softc *sc,
+ struct ath_btcoex_info *btinfo);
+
+static inline void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info,
+ u32 bt_weight,
+ u32 wlan_weight)
+{
+ btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) |
+ SM(wlan_weight, AR_BTCOEX_WL_WGHT);
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 20f74b5b570..3234995e888 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -861,7 +861,7 @@ static void ath9k_hw_9271_pa_cal(struct ath_hw *ah)
REG_WRITE(ah, regList[i][0], regList[i][1]);
}
-static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
+static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
{
u32 regVal;
@@ -877,6 +877,13 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
{ 0x7838, 0 },
};
+ DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
+
+ /* PA CAL is not needed for high power solution */
+ if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
+ AR5416_EEP_TXGAIN_HIGH_POWER)
+ return;
+
if (AR_SREV_9285_11(ah)) {
REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
udelay(10);
@@ -899,13 +906,13 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
- REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
- REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7);
+ REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
udelay(30);
@@ -917,7 +924,6 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
regVal |= (1 << (19 + i));
REG_WRITE(ah, 0x7834, regVal);
udelay(1);
- regVal = REG_READ(ah, 0x7834);
regVal &= (~(0x1 << (19 + i)));
reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
regVal |= (reg_field << (19 + i));
@@ -936,6 +942,17 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
offs_6_1 = offset>>1;
offs_0 = offset & 1;
+ if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
+ if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
+ ah->pacal_info.max_skipcount =
+ 2 * ah->pacal_info.max_skipcount;
+ ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
+ } else {
+ ah->pacal_info.max_skipcount = 1;
+ ah->pacal_info.skipcount = 0;
+ ah->pacal_info.prev_offset = offset;
+ }
+
REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
@@ -982,8 +999,12 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
/* Do periodic PAOffset Cal */
if (AR_SREV_9271(ah))
ath9k_hw_9271_pa_cal(ah);
- else if (AR_SREV_9285_11_OR_LATER(ah))
- ath9k_hw_9285_pa_cal(ah);
+ else if (AR_SREV_9285_11_OR_LATER(ah)) {
+ if (!ah->pacal_info.skipcount)
+ ath9k_hw_9285_pa_cal(ah, false);
+ else
+ ah->pacal_info.skipcount--;
+ }
if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER)
ath9k_olc_temp_compensation(ah);
@@ -1081,7 +1102,7 @@ bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
/* Do PA Calibration */
if (AR_SREV_9285_11_OR_LATER(ah))
- ath9k_hw_9285_pa_cal(ah);
+ ath9k_hw_9285_pa_cal(ah, true);
/* Do NF Calibration after DC offset and other calibrations */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 547e697b905..019bcbba40e 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -110,6 +110,13 @@ struct ath9k_nfcal_hist {
u8 invalidNFcount;
};
+#define MAX_PACAL_SKIPCOUNT 8
+struct ath9k_pacal_info{
+ int32_t prev_offset; /* Previous value of PA offset value */
+ int8_t max_skipcount; /* Max No. of times PACAL can be skipped */
+ int8_t skipcount; /* No. of times the PACAL to be skipped */
+};
+
bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
void ath9k_hw_start_nfcal(struct ath_hw *ah);
void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 9e369208f7d..2be4c225204 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -93,6 +93,8 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
int i, qcuOffset = 0, dcuOffset = 0;
u32 *qcuBase = &val[0], *dcuBase = &val[4];
+ ath9k_ps_wakeup(sc);
+
REG_WRITE(ah, AR_MACMISC,
((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) |
(AR_MACMISC_MISC_OBS_BUS_1 <<
@@ -159,6 +161,8 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"AR_CR: 0x%x \n", REG_READ(ah, AR_CR));
+ ath9k_ps_restore(sc);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 5e56b79d0cb..7241f474833 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -30,6 +30,8 @@ enum ATH_DEBUG {
ATH_DBG_CONFIG = 0x00000200,
ATH_DBG_FATAL = 0x00000400,
ATH_DBG_PS = 0x00000800,
+ ATH_DBG_HWTIMER = 0x00001000,
+ ATH_DBG_BTCOEX = 0x00002000,
ATH_DBG_ANY = 0xffffffff
};
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index 958948bc73f..b6e52d0f8c4 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -143,10 +143,10 @@ void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
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)))) {
+ } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan)) && i > 0 &&
+ freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+ IS_CHAN_2GHZ(chan))) {
lowIndex = i - 1;
break;
}
@@ -198,10 +198,10 @@ void ath9k_hw_get_target_powers(struct ath_hw *ah,
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)))) {
+ if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
+ IS_CHAN_2GHZ(chan)) && i > 0 &&
+ freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
+ IS_CHAN_2GHZ(chan))) {
lowIndex = i - 1;
break;
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 4f3d5ea3481..e340dacc6eb 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2555,6 +2555,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
#endif
}
+ if (ah->ah_sc->sc_flags & SC_OP_BTCOEX_ENABLED)
+ ath9k_hw_btcoex_enable(ah);
+
return 0;
}
@@ -3212,6 +3215,23 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
if (AR_SREV_9100(ah))
return true;
+ if (isr & AR_ISR_GENTMR) {
+ u32 s5_s;
+
+ s5_s = REG_READ(ah, AR_ISR_S5_S);
+ if (isr & AR_ISR_GENTMR) {
+ ah->intr_gen_timer_trigger =
+ MS(s5_s, AR_ISR_S5_GENTIMER_TRIG);
+
+ ah->intr_gen_timer_thresh =
+ MS(s5_s, AR_ISR_S5_GENTIMER_THRESH);
+
+ if (ah->intr_gen_timer_trigger)
+ *masked |= ATH9K_INT_GENTIMER;
+
+ }
+ }
+
if (sync_cause) {
fatal_int =
(sync_cause &
@@ -3486,6 +3506,7 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
{
struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
u16 capField = 0, eeval;
@@ -3662,9 +3683,15 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
if (AR_SREV_9280_10_OR_LATER(ah) && btcoex_enable) {
- pCap->hw_caps |= ATH9K_HW_CAP_BT_COEX;
- ah->btactive_gpio = 6;
- ah->wlanactive_gpio = 5;
+ btcoex_info->btactive_gpio = ATH_BTACTIVE_GPIO;
+ btcoex_info->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
+
+ if (AR_SREV_9285(ah))
+ btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_3WIRE;
+ else
+ btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_2WIRE;
+ } else {
+ btcoex_info->btcoex_scheme = ATH_BTCOEX_CFG_NONE;
}
}
@@ -4069,29 +4096,197 @@ void ath9k_hw_set11nmac2040(struct ath_hw *ah, enum ath9k_ht_macmode mode)
REG_WRITE(ah, AR_2040_MODE, macmode);
}
-/***************************/
-/* Bluetooth Coexistence */
-/***************************/
+/* HW Generic timers configuration */
-void ath9k_hw_btcoex_enable(struct ath_hw *ah)
+static const struct ath_gen_timer_configuration gen_tmr_configuration[] =
+{
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP_TIMER, AR_NDP_PERIOD, AR_TIMER_MODE, 0x0080},
+ {AR_NEXT_NDP2_TIMER, AR_NDP2_PERIOD, AR_NDP2_TIMER_MODE, 0x0001},
+ {AR_NEXT_NDP2_TIMER + 1*4, AR_NDP2_PERIOD + 1*4,
+ AR_NDP2_TIMER_MODE, 0x0002},
+ {AR_NEXT_NDP2_TIMER + 2*4, AR_NDP2_PERIOD + 2*4,
+ AR_NDP2_TIMER_MODE, 0x0004},
+ {AR_NEXT_NDP2_TIMER + 3*4, AR_NDP2_PERIOD + 3*4,
+ AR_NDP2_TIMER_MODE, 0x0008},
+ {AR_NEXT_NDP2_TIMER + 4*4, AR_NDP2_PERIOD + 4*4,
+ AR_NDP2_TIMER_MODE, 0x0010},
+ {AR_NEXT_NDP2_TIMER + 5*4, AR_NDP2_PERIOD + 5*4,
+ AR_NDP2_TIMER_MODE, 0x0020},
+ {AR_NEXT_NDP2_TIMER + 6*4, AR_NDP2_PERIOD + 6*4,
+ AR_NDP2_TIMER_MODE, 0x0040},
+ {AR_NEXT_NDP2_TIMER + 7*4, AR_NDP2_PERIOD + 7*4,
+ AR_NDP2_TIMER_MODE, 0x0080}
+};
+
+/* HW generic timer primitives */
+
+/* compute and clear index of rightmost 1 */
+static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask)
{
- /* connect bt_active to baseband */
- REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
- AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
+ u32 b;
- REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
- AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
+ b = *mask;
+ b &= (0-b);
+ *mask &= ~b;
+ b *= debruijn32;
+ b >>= 27;
+
+ return timer_table->gen_timer_index[b];
+}
+
+u32 ath9k_hw_gettsf32(struct ath_hw *ah)
+{
+ return REG_READ(ah, AR_TSF_L32);
+}
+
+struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
+ void (*trigger)(void *),
+ void (*overflow)(void *),
+ void *arg,
+ u8 timer_index)
+{
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+ struct ath_gen_timer *timer;
+
+ timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL);
+
+ if (timer == NULL) {
+ printk(KERN_DEBUG "Failed to allocate memory"
+ "for hw timer[%d]\n", timer_index);
+ return NULL;
+ }
+
+ /* allocate a hardware generic timer slot */
+ timer_table->timers[timer_index] = timer;
+ timer->index = timer_index;
+ timer->trigger = trigger;
+ timer->overflow = overflow;
+ timer->arg = arg;
+
+ return timer;
+}
+
+void ath_gen_timer_start(struct ath_hw *ah,
+ struct ath_gen_timer *timer,
+ u32 timer_next, u32 timer_period)
+{
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+ u32 tsf;
+
+ BUG_ON(!timer_period);
+
+ set_bit(timer->index, &timer_table->timer_mask.timer_bits);
- /* Set input mux for bt_active to gpio pin */
- REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
- AR_GPIO_INPUT_MUX1_BT_ACTIVE,
- ah->btactive_gpio);
+ tsf = ath9k_hw_gettsf32(ah);
- /* Configure the desired gpio port for input */
- ath9k_hw_cfg_gpio_input(ah, ah->btactive_gpio);
+ DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER, "curent tsf %x period %x"
+ "timer_next %x\n", tsf, timer_period, timer_next);
- /* Configure the desired GPIO port for TX_FRAME output */
- ath9k_hw_cfg_output(ah, ah->wlanactive_gpio,
- AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
+ /*
+ * Pull timer_next forward if the current TSF already passed it
+ * because of software latency
+ */
+ if (timer_next < tsf)
+ timer_next = tsf + timer_period;
+
+ /*
+ * Program generic timer registers
+ */
+ REG_WRITE(ah, gen_tmr_configuration[timer->index].next_addr,
+ timer_next);
+ REG_WRITE(ah, gen_tmr_configuration[timer->index].period_addr,
+ timer_period);
+ REG_SET_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
+ gen_tmr_configuration[timer->index].mode_mask);
+
+ /* Enable both trigger and thresh interrupt masks */
+ REG_SET_BIT(ah, AR_IMR_S5,
+ (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
+ SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
+
+ if ((ah->ah_sc->imask & ATH9K_INT_GENTIMER) == 0) {
+ ath9k_hw_set_interrupts(ah, 0);
+ ah->ah_sc->imask |= ATH9K_INT_GENTIMER;
+ ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
+ }
+}
+
+void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer)
+{
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+
+ if ((timer->index < AR_FIRST_NDP_TIMER) ||
+ (timer->index >= ATH_MAX_GEN_TIMER)) {
+ return;
+ }
+
+ /* Clear generic timer enable bits. */
+ REG_CLR_BIT(ah, gen_tmr_configuration[timer->index].mode_addr,
+ gen_tmr_configuration[timer->index].mode_mask);
+
+ /* Disable both trigger and thresh interrupt masks */
+ REG_CLR_BIT(ah, AR_IMR_S5,
+ (SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_THRESH) |
+ SM(AR_GENTMR_BIT(timer->index), AR_IMR_S5_GENTIMER_TRIG)));
+
+ clear_bit(timer->index, &timer_table->timer_mask.timer_bits);
+
+ /* if no timer is enabled, turn off interrupt mask */
+ if (timer_table->timer_mask.val == 0) {
+ ath9k_hw_set_interrupts(ah, 0);
+ ah->ah_sc->imask &= ~ATH9K_INT_GENTIMER;
+ ath9k_hw_set_interrupts(ah, ah->ah_sc->imask);
+ }
+}
+
+void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer)
+{
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+
+ /* free the hardware generic timer slot */
+ timer_table->timers[timer->index] = NULL;
+ kfree(timer);
+}
+
+/*
+ * Generic Timer Interrupts handling
+ */
+void ath_gen_timer_isr(struct ath_hw *ah)
+{
+ struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
+ struct ath_gen_timer *timer;
+ u32 trigger_mask, thresh_mask, index;
+
+ /* get hardware generic timer interrupt status */
+ trigger_mask = ah->intr_gen_timer_trigger;
+ thresh_mask = ah->intr_gen_timer_thresh;
+ trigger_mask &= timer_table->timer_mask.val;
+ thresh_mask &= timer_table->timer_mask.val;
+
+ trigger_mask &= ~thresh_mask;
+
+ while (thresh_mask) {
+ index = rightmost_index(timer_table, &thresh_mask);
+ timer = timer_table->timers[index];
+ BUG_ON(!timer);
+ DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
+ "TSF overflow for Gen timer %d\n", index);
+ timer->overflow(timer->arg);
+ }
+
+ while (trigger_mask) {
+ index = rightmost_index(timer_table, &trigger_mask);
+ timer = timer_table->timers[index];
+ BUG_ON(!timer);
+ DPRINTF(ah->ah_sc, ATH_DBG_HWTIMER,
+ "Gen timer[%d] trigger\n", index);
+ timer->trigger(timer->arg);
+ }
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 24b30631d93..5ca6ffa7091 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -79,6 +79,7 @@
#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_TX_FRAME 3
+#define AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL 4
#define AR_GPIO_OUTPUT_MUX_AS_MAC_NETWORK_LED 5
#define AR_GPIO_OUTPUT_MUX_AS_MAC_POWER_LED 6
@@ -151,7 +152,6 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_ENHANCEDPM = BIT(14),
ATH9K_HW_CAP_AUTOSLEEP = BIT(15),
ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(16),
- ATH9K_HW_CAP_BT_COEX = BIT(17)
};
enum ath9k_capability_type {
@@ -238,6 +238,7 @@ enum ath9k_int {
ATH9K_INT_GPIO = 0x01000000,
ATH9K_INT_CABEND = 0x02000000,
ATH9K_INT_TSFOOR = 0x04000000,
+ ATH9K_INT_GENTIMER = 0x08000000,
ATH9K_INT_CST = 0x10000000,
ATH9K_INT_GTT = 0x20000000,
ATH9K_INT_FATAL = 0x40000000,
@@ -391,6 +392,41 @@ struct ath9k_hw_version {
u16 analog2GhzRev;
};
+/* Generic TSF timer definitions */
+
+#define ATH_MAX_GEN_TIMER 16
+
+#define AR_GENTMR_BIT(_index) (1 << (_index))
+
+/*
+ * Using de Bruijin sequence to to look up 1's index in a 32 bit number
+ * debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
+ */
+#define debruijn32 0x077CB531UL
+
+struct ath_gen_timer_configuration {
+ u32 next_addr;
+ u32 period_addr;
+ u32 mode_addr;
+ u32 mode_mask;
+};
+
+struct ath_gen_timer {
+ void (*trigger)(void *arg);
+ void (*overflow)(void *arg);
+ void *arg;
+ u8 index;
+};
+
+struct ath_gen_timer_table {
+ u32 gen_timer_index[32];
+ struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER];
+ union {
+ unsigned long timer_bits;
+ u16 val;
+ } timer_mask;
+};
+
struct ath_hw {
struct ath_softc *ah_sc;
struct ath9k_hw_version hw_version;
@@ -414,8 +450,6 @@ struct ath_hw {
u16 rfsilent;
u32 rfkill_gpio;
u32 rfkill_polarity;
- u32 btactive_gpio;
- u32 wlanactive_gpio;
u32 ah_flags;
bool htc_reset_init;
@@ -424,6 +458,7 @@ struct ath_hw {
enum ath9k_power_mode power_mode;
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
+ struct ath9k_pacal_info pacal_info;
struct ar5416Stats stats;
struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
@@ -538,6 +573,10 @@ struct ath_hw {
struct ar5416IniArray iniModesAdditional;
struct ar5416IniArray iniModesRxGain;
struct ar5416IniArray iniModesTxGain;
+
+ u32 intr_gen_timer_trigger;
+ u32 intr_gen_timer_thresh;
+ struct ath_gen_timer_table hw_gen_timers;
};
/* Initialization, Detach, Reset */
@@ -613,6 +652,17 @@ bool ath9k_hw_intrpend(struct ath_hw *ah);
bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked);
enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
-void ath9k_hw_btcoex_enable(struct ath_hw *ah);
+/* Generic hw timer primitives */
+struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
+ void (*trigger)(void *),
+ void (*overflow)(void *),
+ void *arg,
+ u8 timer_index);
+void ath_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer,
+ u32 timer_next, u32 timer_period);
+void ath_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer);
+void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer);
+void ath_gen_timer_isr(struct ath_hw *hw);
+u32 ath9k_hw_gettsf32(struct ath_hw *ah);
#endif
diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h
index 27a86bb7c4c..8622265a030 100644
--- a/drivers/net/wireless/ath/ath9k/initvals.h
+++ b/drivers/net/wireless/ath/ath9k/initvals.h
@@ -4133,7 +4133,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 },
{ 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
{ 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
- { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+ { 0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e },
{ 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
{ 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
{ 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
@@ -4158,7 +4158,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
{ 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
{ 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
- { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 },
+ { 0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f },
{ 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
{ 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
{ 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
@@ -4601,7 +4601,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00008258, 0x00000000 },
{ 0x0000825c, 0x400000ff },
{ 0x00008260, 0x00080922 },
- { 0x00008264, 0xa8a00010 },
+ { 0x00008264, 0x88a00010 },
{ 0x00008270, 0x00000000 },
{ 0x00008274, 0x40000000 },
{ 0x00008278, 0x003e4180 },
@@ -4650,7 +4650,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00009954, 0x5f3ca3de },
{ 0x00009958, 0x2108ecff },
{ 0x00009968, 0x000003ce },
- { 0x00009970, 0x192bb515 },
+ { 0x00009970, 0x192bb514 },
{ 0x00009974, 0x00000000 },
{ 0x00009978, 0x00000001 },
{ 0x0000997c, 0x00000000 },
@@ -4728,7 +4728,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00007800, 0x00140000 },
{ 0x00007804, 0x0e4548d8 },
{ 0x00007808, 0x54214514 },
- { 0x0000780c, 0x02025820 },
+ { 0x0000780c, 0x02025830 },
{ 0x00007810, 0x71c0d388 },
{ 0x00007814, 0x924934a8 },
{ 0x0000781c, 0x00000000 },
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 9b9b4e8ee1e..4fae699a53c 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -439,8 +439,8 @@ static void ath_start_ani(struct ath_softc *sc)
*/
void ath_update_chainmask(struct ath_softc *sc, int is_ht)
{
- if (is_ht ||
- (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)) {
+ if ((sc->sc_flags & SC_OP_SCANNING) || is_ht ||
+ (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE)) {
sc->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
sc->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
} else {
@@ -602,6 +602,10 @@ irqreturn_t ath_isr(int irq, void *dev)
sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
}
+ if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ if (status & ATH9K_INT_GENTIMER)
+ ath_gen_timer_isr(ah);
+
chip_reset:
ath_debug_stat_interrupt(sc, status);
@@ -1279,6 +1283,10 @@ void ath_detach(struct ath_softc *sc)
if (ATH_TXQ_SETUP(sc, i))
ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+ if ((sc->btcoex_info.no_stomp_timer) &&
+ sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_gen_timer_free(sc->sc_ah, sc->btcoex_info.no_stomp_timer);
+
ath9k_hw_detach(sc->sc_ah);
sc->sc_ah = NULL;
ath9k_exit_debug(sc);
@@ -1509,8 +1517,11 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc)
ARRAY_SIZE(ath9k_5ghz_chantable);
}
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BT_COEX)
- ath9k_hw_btcoex_enable(sc->sc_ah);
+ if (sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) {
+ r = ath9k_hw_btcoex_init(ah);
+ if (r)
+ goto bad2;
+ }
return 0;
bad2:
@@ -1992,6 +2003,16 @@ static int ath9k_start(struct ieee80211_hw *hw)
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
+ if ((sc->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) &&
+ !(sc->sc_flags & SC_OP_BTCOEX_ENABLED)) {
+ ath_btcoex_set_weight(&sc->btcoex_info, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
+ ath9k_hw_btcoex_enable(sc->sc_ah);
+
+ if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_btcoex_timer_resume(sc, &sc->btcoex_info);
+ }
+
mutex_unlock:
mutex_unlock(&sc->mutex);
@@ -2125,6 +2146,12 @@ static void ath9k_stop(struct ieee80211_hw *hw)
return; /* another wiphy still in use */
}
+ if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) {
+ ath9k_hw_btcoex_disable(sc->sc_ah);
+ if (sc->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE)
+ ath_btcoex_timer_pause(sc, &sc->btcoex_info);
+ }
+
/* make sure h/w will not generate any interrupt
* before setting the invalid flag. */
ath9k_hw_set_interrupts(sc->sc_ah, 0);
@@ -2713,6 +2740,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ mutex_lock(&sc->mutex);
if (ath9k_wiphy_scanning(sc)) {
printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the "
"same time\n");
@@ -2720,6 +2748,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
* Do not allow the concurrent scanning state for now. This
* could be improved with scanning control moved into ath9k.
*/
+ mutex_unlock(&sc->mutex);
return;
}
@@ -2729,6 +2758,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
spin_lock_bh(&sc->ani_lock);
sc->sc_flags |= SC_OP_SCANNING;
spin_unlock_bh(&sc->ani_lock);
+ mutex_unlock(&sc->mutex);
}
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
@@ -2736,11 +2766,13 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ mutex_lock(&sc->mutex);
spin_lock_bh(&sc->ani_lock);
aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING;
sc->sc_flags |= SC_OP_FULL_RESET;
spin_unlock_bh(&sc->ani_lock);
+ mutex_unlock(&sc->mutex);
}
struct ieee80211_ops ath9k_ops = {
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 7b62c220d5f..52e62daad3c 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -423,11 +423,12 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
if (sc->rx.rxfilter & FIF_PSPOLL)
rfilt |= ATH9K_RX_FILTER_PSPOLL;
- if (sc->sec_wiphy) {
+ if (sc->sec_wiphy || (sc->rx.rxfilter & FIF_OTHER_BSS)) {
/* TODO: only needed if more than one BSSID is in use in
* station/adhoc mode */
- /* TODO: for older chips, may need to add ATH9K_RX_FILTER_PROM
- */
+ /* The following may also be needed for other older chips */
+ if (sc->sc_ah->hw_version.macVersion == AR_SREV_VERSION_9160)
+ rfilt |= ATH9K_RX_FILTER_PROM;
rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
}
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index c9e1ac92d0e..3ddb243f000 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -234,7 +234,15 @@
#define AR_IMR_S5 0x00b8
#define AR_IMR_S5_TIM_TIMER 0x00000010
#define AR_IMR_S5_DTIM_TIMER 0x00000020
-
+#define AR_ISR_S5_GENTIMER_TRIG 0x0000FF80
+#define AR_ISR_S5_GENTIMER_TRIG_S 0
+#define AR_ISR_S5_GENTIMER_THRESH 0xFF800000
+#define AR_ISR_S5_GENTIMER_THRESH_S 16
+#define AR_ISR_S5_S 0x00d8
+#define AR_IMR_S5_GENTIMER_TRIG 0x0000FF80
+#define AR_IMR_S5_GENTIMER_TRIG_S 0
+#define AR_IMR_S5_GENTIMER_THRESH 0xFF800000
+#define AR_IMR_S5_GENTIMER_THRESH_S 16
#define AR_IMR 0x00a0
#define AR_IMR_RXOK 0x00000001
@@ -962,6 +970,8 @@ enum {
#define AR_GPIO_INPUT_EN_VAL_RFSILENT_DEF_S 7
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB 0x00001000
#define AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB_S 12
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB 0x00001000
+#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB_S 1
#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
@@ -970,6 +980,8 @@ enum {
#define AR_GPIO_INPUT_MUX1 0x4058
#define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000
#define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16
+#define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00
+#define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8
#define AR_GPIO_INPUT_MUX2 0x405c
#define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f
@@ -995,6 +1007,8 @@ enum {
#define AR_OBS 0x4080
+#define AR_GPIO_PDPU 0x4088
+
#define AR_PCIE_MSI 0x4094
#define AR_PCIE_MSI_ENABLE 0x00000001
@@ -1428,6 +1442,7 @@ enum {
#define AR_QUIET1_NEXT_QUIET_M 0x0000ffff
#define AR_QUIET1_QUIET_ENABLE 0x00010000
#define AR_QUIET1_QUIET_ACK_CTS_ENABLE 0x00020000
+#define AR_QUIET1_QUIET_ACK_CTS_ENABLE_S 17
#define AR_QUIET2 0x8100
#define AR_QUIET2_QUIET_PERIOD_S 0
#define AR_QUIET2_QUIET_PERIOD_M 0x0000ffff
@@ -1473,6 +1488,8 @@ enum {
#define AR_PCU_CLEAR_VMF 0x01000000
#define AR_PCU_CLEAR_BA_VALID 0x04000000
+#define AR_PCU_BT_ANT_PREVENT_RX 0x00100000
+#define AR_PCU_BT_ANT_PREVENT_RX_S 20
#define AR_FILT_OFDM 0x8124
#define AR_FILT_OFDM_COUNT 0x00FFFFFF
@@ -1500,6 +1517,46 @@ enum {
#define AR_PHY_ERR_3_COUNT 0x00FFFFFF
#define AR_PHY_ERR_MASK_3 0x816c
+#define AR_BT_COEX_MODE 0x8170
+#define AR_BT_TIME_EXTEND 0x000000ff
+#define AR_BT_TIME_EXTEND_S 0
+#define AR_BT_TXSTATE_EXTEND 0x00000100
+#define AR_BT_TXSTATE_EXTEND_S 8
+#define AR_BT_TX_FRAME_EXTEND 0x00000200
+#define AR_BT_TX_FRAME_EXTEND_S 9
+#define AR_BT_MODE 0x00000c00
+#define AR_BT_MODE_S 10
+#define AR_BT_QUIET 0x00001000
+#define AR_BT_QUIET_S 12
+#define AR_BT_QCU_THRESH 0x0001e000
+#define AR_BT_QCU_THRESH_S 13
+#define AR_BT_RX_CLEAR_POLARITY 0x00020000
+#define AR_BT_RX_CLEAR_POLARITY_S 17
+#define AR_BT_PRIORITY_TIME 0x00fc0000
+#define AR_BT_PRIORITY_TIME_S 18
+#define AR_BT_FIRST_SLOT_TIME 0xff000000
+#define AR_BT_FIRST_SLOT_TIME_S 24
+
+#define AR_BT_COEX_WEIGHT 0x8174
+#define AR_BT_COEX_WGHT 0xff55
+#define AR_STOMP_ALL_WLAN_WGHT 0xffcc
+#define AR_STOMP_LOW_WLAN_WGHT 0xaaa8
+#define AR_STOMP_NONE_WLAN_WGHT 0xaa00
+#define AR_BTCOEX_BT_WGHT 0x0000ffff
+#define AR_BTCOEX_BT_WGHT_S 0
+#define AR_BTCOEX_WL_WGHT 0xffff0000
+#define AR_BTCOEX_WL_WGHT_S 16
+
+#define AR_BT_COEX_MODE2 0x817c
+#define AR_BT_BCN_MISS_THRESH 0x000000ff
+#define AR_BT_BCN_MISS_THRESH_S 0
+#define AR_BT_BCN_MISS_CNT 0x0000ff00
+#define AR_BT_BCN_MISS_CNT_S 8
+#define AR_BT_HOLD_RX_CLEAR 0x00010000
+#define AR_BT_HOLD_RX_CLEAR_S 16
+#define AR_BT_DISABLE_BT_ANT 0x00100000
+#define AR_BT_DISABLE_BT_ANT_S 20
+
#define AR_TXSIFS 0x81d0
#define AR_TXSIFS_TIME 0x000000FF
#define AR_TXSIFS_TX_LATENCY 0x00000F00
@@ -1516,7 +1573,10 @@ enum {
#define AR_TXOP_8_11 0x81f8
#define AR_TXOP_12_15 0x81fc
-
+#define AR_NEXT_NDP2_TIMER 0x8180
+#define AR_FIRST_NDP_TIMER 7
+#define AR_NDP2_PERIOD 0x81a0
+#define AR_NDP2_TIMER_MODE 0x81c0
#define AR_NEXT_TBTT_TIMER 0x8200
#define AR_NEXT_DMA_BEACON_ALERT 0x8204
#define AR_NEXT_SWBA 0x8208
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 87762da0383..42551a48c8a 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -493,7 +493,12 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
return 0;
- aggr_limit = min(max_4ms_framelen, (u32)ATH_AMPDU_LIMIT_MAX);
+ if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
+ aggr_limit = min((max_4ms_framelen * 3) / 8,
+ (u32)ATH_AMPDU_LIMIT_MAX);
+ else
+ aggr_limit = min(max_4ms_framelen,
+ (u32)ATH_AMPDU_LIMIT_MAX);
/*
* h/w can accept aggregates upto 16 bit lengths (65535).
@@ -872,7 +877,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
return &sc->tx.txq[qnum];
}
-static int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
+int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
{
int qnum;