ath9k: implement rx/tx antenna control
SVN-Revision: 28107
This commit is contained in:
parent
45d80c30a2
commit
8a26e3d6c7
6 changed files with 893 additions and 31 deletions
|
@ -22,36 +22,53 @@
|
||||||
}
|
}
|
||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||||
@@ -226,6 +226,7 @@ static int ath_set_channel(struct ath_so
|
@@ -1654,9 +1654,10 @@ static int ath9k_config(struct ieee80211
|
||||||
bool fastcc = true, stopped;
|
|
||||||
struct ieee80211_channel *channel = hw->conf.channel;
|
|
||||||
struct ath9k_hw_cal_data *caldata = NULL;
|
|
||||||
+ u32 oldflags;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (sc->sc_flags & SC_OP_INVALID)
|
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||||
@@ -268,6 +269,24 @@ static int ath_set_channel(struct ath_so
|
struct ieee80211_channel *curchan = hw->conf.channel;
|
||||||
if (!stopped || !(sc->sc_flags & SC_OP_OFFCHANNEL))
|
- struct ath9k_channel old_chan;
|
||||||
fastcc = false;
|
+ struct ath9k_channel old_chan, *hchan;
|
||||||
|
int pos = curchan->hw_value;
|
||||||
|
int old_pos = -1;
|
||||||
|
+ u32 oldflags;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
+ oldflags = hchan->channelFlags;
|
if (ah->curchan)
|
||||||
+ switch (sc->chan_bw) {
|
@@ -1709,7 +1710,23 @@ static int ath9k_config(struct ieee80211
|
||||||
+ case 5:
|
memset(&sc->survey[pos], 0, sizeof(struct survey_info));
|
||||||
+ hchan->channelFlags &= ~CHANNEL_HALF;
|
}
|
||||||
+ hchan->channelFlags |= CHANNEL_QUARTER;
|
|
||||||
+ break;
|
- if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
|
||||||
+ case 10:
|
+ hchan = &sc->sc_ah->channels[pos];
|
||||||
+ hchan->channelFlags &= ~CHANNEL_QUARTER;
|
+ oldflags = hchan->channelFlags;
|
||||||
+ hchan->channelFlags |= CHANNEL_HALF;
|
+ switch (sc->chan_bw) {
|
||||||
+ break;
|
+ case 5:
|
||||||
+ default:
|
+ hchan->channelFlags &= ~CHANNEL_HALF;
|
||||||
+ hchan->channelFlags &= ~(CHANNEL_HALF | CHANNEL_QUARTER);
|
+ hchan->channelFlags |= CHANNEL_QUARTER;
|
||||||
+ break;
|
+ break;
|
||||||
+ }
|
+ case 10:
|
||||||
|
+ hchan->channelFlags &= ~CHANNEL_QUARTER;
|
||||||
|
+ hchan->channelFlags |= CHANNEL_HALF;
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ hchan->channelFlags &= ~(CHANNEL_HALF | CHANNEL_QUARTER);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
+
|
+
|
||||||
+ if (oldflags != hchan->channelFlags)
|
+ if (ath_set_channel(sc, hw, hchan) < 0) {
|
||||||
+ fastcc = false;
|
ath_err(common, "Unable to set channel\n");
|
||||||
+
|
mutex_unlock(&sc->mutex);
|
||||||
if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
|
return -EINVAL;
|
||||||
caldata = &sc->caldata;
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
|
@@ -1504,6 +1504,10 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
||||||
|
}
|
||||||
|
ah->noise = ath9k_hw_getchan_noise(ah, chan);
|
||||||
|
|
||||||
|
+ if (!ah->curchan || ((ah->curchan->channelFlags ^ chan->channelFlags) &
|
||||||
|
+ (CHANNEL_HALF | CHANNEL_QUARTER)))
|
||||||
|
+ bChannelChange = false;
|
||||||
|
+
|
||||||
|
if (bChannelChange &&
|
||||||
|
(ah->chip_fullsleep != true) &&
|
||||||
|
(ah->curchan != NULL) &&
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/drivers/net/wireless/ath/ath9k/main.c
|
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||||
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||||
@@ -1734,6 +1734,8 @@ static int ath9k_config(struct ieee80211
|
@@ -1732,6 +1732,8 @@ static int ath9k_config(struct ieee80211
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
/*
|
/*
|
||||||
* The most recent snapshot of channel->noisefloor for the old
|
* The most recent snapshot of channel->noisefloor for the old
|
||||||
* channel is only available after the hardware reset. Copy it to
|
* channel is only available after the hardware reset. Copy it to
|
||||||
@@ -1751,6 +1753,7 @@ static int ath9k_config(struct ieee80211
|
@@ -1749,6 +1751,7 @@ static int ath9k_config(struct ieee80211
|
||||||
ath9k_cmn_update_txpow(ah, sc->curtxpow,
|
ath9k_cmn_update_txpow(ah, sc->curtxpow,
|
||||||
sc->config.txpowlimit, &sc->curtxpow);
|
sc->config.txpowlimit, &sc->curtxpow);
|
||||||
ath9k_ps_restore(sc);
|
ath9k_ps_restore(sc);
|
||||||
|
|
273
package/mac80211/patches/580-ath9k_remove_common_chainmask.patch
Normal file
273
package/mac80211/patches/580-ath9k_remove_common_chainmask.patch
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
--- a/drivers/net/wireless/ath/ath.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath.h
|
||||||
|
@@ -140,9 +140,6 @@ struct ath_common {
|
||||||
|
u8 curbssid[ETH_ALEN];
|
||||||
|
u8 bssidmask[ETH_ALEN];
|
||||||
|
|
||||||
|
- u8 tx_chainmask;
|
||||||
|
- u8 rx_chainmask;
|
||||||
|
-
|
||||||
|
u32 rx_bufsize;
|
||||||
|
|
||||||
|
u32 keymax;
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
|
||||||
|
@@ -113,7 +113,7 @@ static int ar9003_get_training_power_5g(
|
||||||
|
if (delta > scale)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
- switch (get_streams(common->tx_chainmask)) {
|
||||||
|
+ switch (get_streams(ah->txchainmask)) {
|
||||||
|
case 1:
|
||||||
|
delta = 6;
|
||||||
|
break;
|
||||||
|
@@ -126,7 +126,7 @@ static int ar9003_get_training_power_5g(
|
||||||
|
default:
|
||||||
|
delta = 0;
|
||||||
|
ath_dbg(common, ATH_DBG_CALIBRATE,
|
||||||
|
- "Invalid tx-chainmask: %u\n", common->tx_chainmask);
|
||||||
|
+ "Invalid tx-chainmask: %u\n", ah->txchainmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
power += delta;
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||||
|
@@ -318,7 +318,6 @@ static void ath_paprd_activate(struct at
|
||||||
|
{
|
||||||
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
|
struct ath9k_hw_cal_data *caldata = ah->caldata;
|
||||||
|
- struct ath_common *common = ath9k_hw_common(ah);
|
||||||
|
int chain;
|
||||||
|
|
||||||
|
if (!caldata || !caldata->paprd_done)
|
||||||
|
@@ -327,7 +326,7 @@ static void ath_paprd_activate(struct at
|
||||||
|
ath9k_ps_wakeup(sc);
|
||||||
|
ar9003_paprd_enable(ah, false);
|
||||||
|
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
|
||||||
|
- if (!(common->tx_chainmask & BIT(chain)))
|
||||||
|
+ if (!(ah->txchainmask & BIT(chain)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ar9003_paprd_populate_single_table(ah, caldata, chain);
|
||||||
|
@@ -414,7 +413,7 @@ void ath_paprd_calibrate(struct work_str
|
||||||
|
memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
|
||||||
|
|
||||||
|
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
|
||||||
|
- if (!(common->tx_chainmask & BIT(chain)))
|
||||||
|
+ if (!(ah->txchainmask & BIT(chain)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
chain_ok = 0;
|
||||||
|
@@ -535,7 +534,7 @@ void ath_ani_calibrate(unsigned long dat
|
||||||
|
if (longcal || shortcal) {
|
||||||
|
common->ani.caldone =
|
||||||
|
ath9k_hw_calibrate(ah, ah->curchan,
|
||||||
|
- common->rx_chainmask, longcal);
|
||||||
|
+ ah->rxchainmask, longcal);
|
||||||
|
}
|
||||||
|
|
||||||
|
ath9k_ps_restore(sc);
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/hw.c
|
||||||
|
@@ -1485,9 +1485,6 @@ int ath9k_hw_reset(struct ath_hw *ah, st
|
||||||
|
u64 tsf = 0;
|
||||||
|
int i, r;
|
||||||
|
|
||||||
|
- ah->txchainmask = common->tx_chainmask;
|
||||||
|
- ah->rxchainmask = common->rx_chainmask;
|
||||||
|
-
|
||||||
|
if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
@@ -2105,6 +2102,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw
|
||||||
|
|
||||||
|
pCap->tx_chainmask = fixup_chainmask(chip_chainmask, pCap->tx_chainmask);
|
||||||
|
pCap->rx_chainmask = fixup_chainmask(chip_chainmask, pCap->rx_chainmask);
|
||||||
|
+ ah->txchainmask = pCap->tx_chainmask;
|
||||||
|
+ ah->rxchainmask = pCap->rx_chainmask;
|
||||||
|
|
||||||
|
ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA;
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/xmit.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
|
||||||
|
@@ -1655,7 +1655,7 @@ u8 ath_txchainmask_reduction(struct ath_
|
||||||
|
|
||||||
|
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
|
||||||
|
{
|
||||||
|
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
|
+ struct ath_hw *ah = sc->sc_ah;
|
||||||
|
struct ath9k_11n_rate_series series[4];
|
||||||
|
struct sk_buff *skb;
|
||||||
|
struct ieee80211_tx_info *tx_info;
|
||||||
|
@@ -1715,7 +1715,7 @@ static void ath_buf_set_rate(struct ath_
|
||||||
|
/* MCS rates */
|
||||||
|
series[i].Rate = rix | 0x80;
|
||||||
|
series[i].ChSel = ath_txchainmask_reduction(sc,
|
||||||
|
- common->tx_chainmask, series[i].Rate);
|
||||||
|
+ ah->txchainmask, series[i].Rate);
|
||||||
|
series[i].PktDuration = ath_pkt_duration(sc, rix, len,
|
||||||
|
is_40, is_sgi, is_sp);
|
||||||
|
if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
|
||||||
|
@@ -1740,10 +1740,10 @@ static void ath_buf_set_rate(struct ath_
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bf->bf_state.bfs_paprd)
|
||||||
|
- series[i].ChSel = common->tx_chainmask;
|
||||||
|
+ series[i].ChSel = ah->txchainmask;
|
||||||
|
else
|
||||||
|
series[i].ChSel = ath_txchainmask_reduction(sc,
|
||||||
|
- common->tx_chainmask, series[i].Rate);
|
||||||
|
+ ah->txchainmask, series[i].Rate);
|
||||||
|
|
||||||
|
series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
|
||||||
|
phy, rate->bitrate * 100, len, rix, is_sp);
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/beacon.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
|
||||||
|
@@ -107,7 +107,7 @@ static void ath_beacon_setup(struct ath_
|
||||||
|
series[0].Tries = 1;
|
||||||
|
series[0].Rate = rate;
|
||||||
|
series[0].ChSel = ath_txchainmask_reduction(sc,
|
||||||
|
- common->tx_chainmask, series[0].Rate);
|
||||||
|
+ ah->txchainmask, series[0].Rate);
|
||||||
|
series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
|
||||||
|
ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration,
|
||||||
|
series, 4, 0);
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/debug.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/debug.c
|
||||||
|
@@ -95,11 +95,11 @@ static ssize_t read_file_tx_chainmask(st
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct ath_softc *sc = file->private_data;
|
||||||
|
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
|
+ struct ath_hw *ah = sc->sc_ah;
|
||||||
|
char buf[32];
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
- len = sprintf(buf, "0x%08x\n", common->tx_chainmask);
|
||||||
|
+ len = sprintf(buf, "0x%08x\n", ah->txchainmask);
|
||||||
|
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -107,7 +107,7 @@ static ssize_t write_file_tx_chainmask(s
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct ath_softc *sc = file->private_data;
|
||||||
|
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
|
+ struct ath_hw *ah = sc->sc_ah;
|
||||||
|
unsigned long mask;
|
||||||
|
char buf[32];
|
||||||
|
ssize_t len;
|
||||||
|
@@ -120,8 +120,8 @@ static ssize_t write_file_tx_chainmask(s
|
||||||
|
if (strict_strtoul(buf, 0, &mask))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
- common->tx_chainmask = mask;
|
||||||
|
- sc->sc_ah->caps.tx_chainmask = mask;
|
||||||
|
+ ah->txchainmask = mask;
|
||||||
|
+ ah->caps.tx_chainmask = mask;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -138,11 +138,11 @@ static ssize_t read_file_rx_chainmask(st
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct ath_softc *sc = file->private_data;
|
||||||
|
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
|
+ struct ath_hw *ah = sc->sc_ah;
|
||||||
|
char buf[32];
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
- len = sprintf(buf, "0x%08x\n", common->rx_chainmask);
|
||||||
|
+ len = sprintf(buf, "0x%08x\n", ah->rxchainmask);
|
||||||
|
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -150,7 +150,7 @@ static ssize_t write_file_rx_chainmask(s
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct ath_softc *sc = file->private_data;
|
||||||
|
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
|
+ struct ath_hw *ah = sc->sc_ah;
|
||||||
|
unsigned long mask;
|
||||||
|
char buf[32];
|
||||||
|
ssize_t len;
|
||||||
|
@@ -163,8 +163,8 @@ static ssize_t write_file_rx_chainmask(s
|
||||||
|
if (strict_strtoul(buf, 0, &mask))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
- common->rx_chainmask = mask;
|
||||||
|
- sc->sc_ah->caps.rx_chainmask = mask;
|
||||||
|
+ ah->rxchainmask = mask;
|
||||||
|
+ ah->caps.rx_chainmask = mask;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
|
||||||
|
@@ -509,8 +509,8 @@ static void setup_ht_cap(struct ath9k_ht
|
||||||
|
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
|
||||||
|
|
||||||
|
/* ath9k_htc supports only 1 or 2 stream devices */
|
||||||
|
- tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2);
|
||||||
|
- rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2);
|
||||||
|
+ tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2);
|
||||||
|
+ rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2);
|
||||||
|
|
||||||
|
ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
|
"TX streams %d, RX streams: %d\n",
|
||||||
|
@@ -601,9 +601,6 @@ static void ath9k_init_misc(struct ath9k
|
||||||
|
{
|
||||||
|
struct ath_common *common = ath9k_hw_common(priv->ah);
|
||||||
|
|
||||||
|
- common->tx_chainmask = priv->ah->caps.tx_chainmask;
|
||||||
|
- common->rx_chainmask = priv->ah->caps.rx_chainmask;
|
||||||
|
-
|
||||||
|
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
|
||||||
|
|
||||||
|
priv->ah->opmode = NL80211_IFTYPE_STATION;
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
|
||||||
|
@@ -826,8 +826,7 @@ void ath9k_htc_ani_work(struct work_stru
|
||||||
|
if (longcal || shortcal)
|
||||||
|
common->ani.caldone =
|
||||||
|
ath9k_hw_calibrate(ah, ah->curchan,
|
||||||
|
- common->rx_chainmask,
|
||||||
|
- longcal);
|
||||||
|
+ ah->rxchainmask, longcal);
|
||||||
|
|
||||||
|
ath9k_htc_ps_restore(priv);
|
||||||
|
}
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||||
|
@@ -270,8 +270,8 @@ static void setup_ht_cap(struct ath_soft
|
||||||
|
|
||||||
|
/* set up supported mcs set */
|
||||||
|
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
|
||||||
|
- tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, max_streams);
|
||||||
|
- rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, max_streams);
|
||||||
|
+ tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams);
|
||||||
|
+ rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams);
|
||||||
|
|
||||||
|
ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
|
"TX streams %d, RX streams: %d\n",
|
||||||
|
@@ -506,9 +506,6 @@ static void ath9k_init_misc(struct ath_s
|
||||||
|
sc->sc_flags |= SC_OP_RXAGGR;
|
||||||
|
}
|
||||||
|
|
||||||
|
- common->tx_chainmask = sc->sc_ah->caps.tx_chainmask;
|
||||||
|
- common->rx_chainmask = sc->sc_ah->caps.rx_chainmask;
|
||||||
|
-
|
||||||
|
ath9k_hw_set_diversity(sc->sc_ah, true);
|
||||||
|
sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
|
||||||
|
|
||||||
|
@@ -645,10 +642,8 @@ static void ath9k_init_band_txpower(stru
|
||||||
|
static void ath9k_init_txpower_limits(struct ath_softc *sc)
|
||||||
|
{
|
||||||
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
|
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
|
struct ath9k_channel *curchan = ah->curchan;
|
||||||
|
|
||||||
|
- ah->txchainmask = common->tx_chainmask;
|
||||||
|
if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
|
||||||
|
ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ);
|
||||||
|
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
|
343
package/mac80211/patches/581-ath9k_merge_reset_functions.patch
Normal file
343
package/mac80211/patches/581-ath9k_merge_reset_functions.patch
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||||
|
@@ -212,83 +212,39 @@ static int ath_update_survey_stats(struc
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
-/*
|
||||||
|
- * 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.
|
||||||
|
-*/
|
||||||
|
-static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||||
|
- struct ath9k_channel *hchan)
|
||||||
|
+static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx)
|
||||||
|
{
|
||||||
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
|
- struct ath_common *common = ath9k_hw_common(ah);
|
||||||
|
- struct ieee80211_conf *conf = &common->hw->conf;
|
||||||
|
- bool fastcc = true, stopped;
|
||||||
|
- struct ieee80211_channel *channel = hw->conf.channel;
|
||||||
|
- struct ath9k_hw_cal_data *caldata = NULL;
|
||||||
|
- int r;
|
||||||
|
+ bool ret;
|
||||||
|
|
||||||
|
- if (sc->sc_flags & SC_OP_INVALID)
|
||||||
|
- return -EIO;
|
||||||
|
+ ieee80211_stop_queues(sc->hw);
|
||||||
|
|
||||||
|
sc->hw_busy_count = 0;
|
||||||
|
-
|
||||||
|
- del_timer_sync(&common->ani.timer);
|
||||||
|
cancel_work_sync(&sc->paprd_work);
|
||||||
|
cancel_work_sync(&sc->hw_check_work);
|
||||||
|
cancel_delayed_work_sync(&sc->tx_complete_work);
|
||||||
|
cancel_delayed_work_sync(&sc->hw_pll_work);
|
||||||
|
|
||||||
|
- ath9k_ps_wakeup(sc);
|
||||||
|
-
|
||||||
|
- spin_lock_bh(&sc->sc_pcu_lock);
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * 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_disable_interrupts(ah);
|
||||||
|
- stopped = ath_drain_all_txq(sc, false);
|
||||||
|
|
||||||
|
- if (!ath_stoprecv(sc))
|
||||||
|
- stopped = false;
|
||||||
|
-
|
||||||
|
- if (!ath9k_hw_check_alive(ah))
|
||||||
|
- stopped = false;
|
||||||
|
-
|
||||||
|
- /* XXX: do not flush receive queue here. We don't want
|
||||||
|
- * to flush data frames already in queue because of
|
||||||
|
- * changing channel. */
|
||||||
|
+ ret = ath_drain_all_txq(sc, retry_tx);
|
||||||
|
|
||||||
|
- if (!stopped || !(sc->sc_flags & SC_OP_OFFCHANNEL))
|
||||||
|
- fastcc = false;
|
||||||
|
+ if (!ath_stoprecv(sc))
|
||||||
|
+ ret = false;
|
||||||
|
|
||||||
|
- if (!(sc->sc_flags & SC_OP_OFFCHANNEL))
|
||||||
|
- caldata = &sc->caldata;
|
||||||
|
+ ath_flushrecv(sc);
|
||||||
|
|
||||||
|
- ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
|
- "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n",
|
||||||
|
- sc->sc_ah->curchan->channel,
|
||||||
|
- channel->center_freq, conf_is_ht40(conf),
|
||||||
|
- fastcc);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
|
||||||
|
- r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
|
||||||
|
- if (r) {
|
||||||
|
- ath_err(common,
|
||||||
|
- "Unable to reset channel (%u MHz), reset status %d\n",
|
||||||
|
- channel->center_freq, r);
|
||||||
|
- goto ps_restore;
|
||||||
|
- }
|
||||||
|
+static bool ath_complete_reset(struct ath_softc *sc)
|
||||||
|
+{
|
||||||
|
+ struct ath_hw *ah = sc->sc_ah;
|
||||||
|
+ struct ath_common *common = ath9k_hw_common(ah);
|
||||||
|
|
||||||
|
if (ath_startrecv(sc) != 0) {
|
||||||
|
ath_err(common, "Unable to restart recv logic\n");
|
||||||
|
- r = -EIO;
|
||||||
|
- goto ps_restore;
|
||||||
|
+ return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ath9k_cmn_update_txpow(ah, sc->curtxpow,
|
||||||
|
@@ -299,18 +255,84 @@ static int ath_set_channel(struct ath_so
|
||||||
|
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
|
||||||
|
if (sc->sc_flags & SC_OP_BEACONS)
|
||||||
|
ath_set_beacon(sc);
|
||||||
|
+
|
||||||
|
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
|
||||||
|
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
|
||||||
|
if (!common->disable_ani)
|
||||||
|
ath_start_ani(common);
|
||||||
|
}
|
||||||
|
|
||||||
|
- ps_restore:
|
||||||
|
- ieee80211_wake_queues(hw);
|
||||||
|
+ ieee80211_wake_queues(sc->hw);
|
||||||
|
+
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
|
||||||
|
+ bool retry_tx)
|
||||||
|
+{
|
||||||
|
+ struct ath_hw *ah = sc->sc_ah;
|
||||||
|
+ struct ath_common *common = ath9k_hw_common(ah);
|
||||||
|
+ struct ath9k_hw_cal_data *caldata = NULL;
|
||||||
|
+ bool fastcc = true;
|
||||||
|
+ int r;
|
||||||
|
+
|
||||||
|
+ if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) {
|
||||||
|
+ fastcc = false;
|
||||||
|
+ caldata = &sc->caldata;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
+ if (!hchan) {
|
||||||
|
+ fastcc = false;
|
||||||
|
+ hchan = ah->curchan;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (fastcc && !ath9k_hw_check_alive(ah))
|
||||||
|
+ fastcc = false;
|
||||||
|
+
|
||||||
|
+ if (!ath_prepare_reset(sc, retry_tx))
|
||||||
|
+ fastcc = false;
|
||||||
|
+
|
||||||
|
+ ath_dbg(common, ATH_DBG_CONFIG,
|
||||||
|
+ "Reset to %u MHz, HT40: %d fastcc: %d\n",
|
||||||
|
+ hchan->channel, !!(hchan->channelFlags & (CHANNEL_HT40MINUS |
|
||||||
|
+ CHANNEL_HT40PLUS)),
|
||||||
|
+ fastcc);
|
||||||
|
+
|
||||||
|
+ r = ath9k_hw_reset(ah, hchan, caldata, fastcc);
|
||||||
|
+ if (r) {
|
||||||
|
+ ath_err(common,
|
||||||
|
+ "Unable to reset channel, reset status %d\n", r);
|
||||||
|
+ return r;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!ath_complete_reset(sc))
|
||||||
|
+ return -EIO;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * 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.
|
||||||
|
+*/
|
||||||
|
+static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
|
||||||
|
+ struct ath9k_channel *hchan)
|
||||||
|
+{
|
||||||
|
+ int r;
|
||||||
|
+
|
||||||
|
+ if (sc->sc_flags & SC_OP_INVALID)
|
||||||
|
+ return -EIO;
|
||||||
|
+
|
||||||
|
+ ath9k_ps_wakeup(sc);
|
||||||
|
+
|
||||||
|
+ spin_lock_bh(&sc->sc_pcu_lock);
|
||||||
|
+ r = ath_reset_internal(sc, hchan, false);
|
||||||
|
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||||
|
|
||||||
|
ath9k_ps_restore(sc);
|
||||||
|
+
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -893,28 +915,13 @@ static void ath_radio_enable(struct ath_
|
||||||
|
channel->center_freq, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
|
||||||
|
- sc->config.txpowlimit, &sc->curtxpow);
|
||||||
|
- if (ath_startrecv(sc) != 0) {
|
||||||
|
- ath_err(common, "Unable to restart recv logic\n");
|
||||||
|
- goto out;
|
||||||
|
- }
|
||||||
|
- if (sc->sc_flags & SC_OP_BEACONS)
|
||||||
|
- ath_set_beacon(sc); /* restart beacons */
|
||||||
|
-
|
||||||
|
- /* Re-Enable interrupts */
|
||||||
|
- ath9k_hw_set_interrupts(ah, ah->imask);
|
||||||
|
- ath9k_hw_enable_interrupts(ah);
|
||||||
|
+ ath_complete_reset(sc);
|
||||||
|
|
||||||
|
/* Enable LED */
|
||||||
|
ath9k_hw_cfg_output(ah, ah->led_pin,
|
||||||
|
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||||
|
ath9k_hw_set_gpio(ah, ah->led_pin, 0);
|
||||||
|
|
||||||
|
- ieee80211_wake_queues(hw);
|
||||||
|
- ieee80211_queue_delayed_work(hw, &sc->hw_pll_work, HZ/2);
|
||||||
|
-
|
||||||
|
-out:
|
||||||
|
spin_unlock_bh(&sc->sc_pcu_lock);
|
||||||
|
|
||||||
|
ath9k_ps_restore(sc);
|
||||||
|
@@ -942,13 +949,7 @@ void ath_radio_disable(struct ath_softc
|
||||||
|
ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* Disable interrupts */
|
||||||
|
- ath9k_hw_disable_interrupts(ah);
|
||||||
|
-
|
||||||
|
- ath_drain_all_txq(sc, false); /* clear pending tx frames */
|
||||||
|
-
|
||||||
|
- ath_stoprecv(sc); /* turn off frame recv */
|
||||||
|
- ath_flushrecv(sc); /* flush recv queue */
|
||||||
|
+ ath_prepare_reset(sc, false);
|
||||||
|
|
||||||
|
if (!ah->curchan)
|
||||||
|
ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
|
||||||
|
@@ -970,48 +971,11 @@ void ath_radio_disable(struct ath_softc
|
||||||
|
|
||||||
|
int ath_reset(struct ath_softc *sc, bool retry_tx)
|
||||||
|
{
|
||||||
|
- struct ath_hw *ah = sc->sc_ah;
|
||||||
|
- struct ath_common *common = ath9k_hw_common(ah);
|
||||||
|
- struct ieee80211_hw *hw = sc->hw;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
- sc->hw_busy_count = 0;
|
||||||
|
-
|
||||||
|
- /* Stop ANI */
|
||||||
|
-
|
||||||
|
- del_timer_sync(&common->ani.timer);
|
||||||
|
-
|
||||||
|
ath9k_ps_wakeup(sc);
|
||||||
|
|
||||||
|
- ieee80211_stop_queues(hw);
|
||||||
|
-
|
||||||
|
- ath9k_hw_disable_interrupts(ah);
|
||||||
|
- ath_drain_all_txq(sc, retry_tx);
|
||||||
|
-
|
||||||
|
- ath_stoprecv(sc);
|
||||||
|
- ath_flushrecv(sc);
|
||||||
|
-
|
||||||
|
- r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false);
|
||||||
|
- if (r)
|
||||||
|
- ath_err(common,
|
||||||
|
- "Unable to reset hardware; reset status %d\n", r);
|
||||||
|
-
|
||||||
|
- if (ath_startrecv(sc) != 0)
|
||||||
|
- ath_err(common, "Unable to start recv logic\n");
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * 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.
|
||||||
|
- */
|
||||||
|
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
|
||||||
|
- sc->config.txpowlimit, &sc->curtxpow);
|
||||||
|
-
|
||||||
|
- if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL)))
|
||||||
|
- ath_set_beacon(sc); /* restart beacons */
|
||||||
|
-
|
||||||
|
- ath9k_hw_set_interrupts(ah, ah->imask);
|
||||||
|
- ath9k_hw_enable_interrupts(ah);
|
||||||
|
+ r = ath_reset_internal(sc, NULL, retry_tx);
|
||||||
|
|
||||||
|
if (retry_tx) {
|
||||||
|
int i;
|
||||||
|
@@ -1024,12 +988,6 @@ int ath_reset(struct ath_softc *sc, bool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- ieee80211_wake_queues(hw);
|
||||||
|
-
|
||||||
|
- /* Start ANI */
|
||||||
|
- if (!common->disable_ani)
|
||||||
|
- ath_start_ani(common);
|
||||||
|
-
|
||||||
|
ath9k_ps_restore(sc);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
@@ -1081,28 +1039,6 @@ static int ath9k_start(struct ieee80211_
|
||||||
|
goto mutex_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- * This is needed only to setup initial state
|
||||||
|
- * but it's best done after a reset.
|
||||||
|
- */
|
||||||
|
- ath9k_cmn_update_txpow(ah, sc->curtxpow,
|
||||||
|
- sc->config.txpowlimit, &sc->curtxpow);
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * 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) {
|
||||||
|
- ath_err(common, "Unable to start recv logic\n");
|
||||||
|
- r = -EIO;
|
||||||
|
- spin_unlock_bh(&sc->sc_pcu_lock);
|
||||||
|
- goto mutex_unlock;
|
||||||
|
- }
|
||||||
|
- spin_unlock_bh(&sc->sc_pcu_lock);
|
||||||
|
-
|
||||||
|
/* Setup our intr mask. */
|
||||||
|
ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
|
||||||
|
ATH9K_INT_RXORN | ATH9K_INT_FATAL |
|
||||||
|
@@ -1125,12 +1061,14 @@ static int ath9k_start(struct ieee80211_
|
||||||
|
|
||||||
|
/* Disable BMISS interrupt when we're not associated */
|
||||||
|
ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
|
||||||
|
- ath9k_hw_set_interrupts(ah, ah->imask);
|
||||||
|
- ath9k_hw_enable_interrupts(ah);
|
||||||
|
|
||||||
|
- ieee80211_wake_queues(hw);
|
||||||
|
+ if (!ath_complete_reset(sc)) {
|
||||||
|
+ r = -EIO;
|
||||||
|
+ spin_unlock_bh(&sc->sc_pcu_lock);
|
||||||
|
+ goto mutex_unlock;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
|
||||||
|
+ spin_unlock_bh(&sc->sc_pcu_lock);
|
||||||
|
|
||||||
|
if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
|
||||||
|
!ah->btcoex_hw.enabled) {
|
50
package/mac80211/patches/582-ath9k_antdiv_comb_cb.patch
Normal file
50
package/mac80211/patches/582-ath9k_antdiv_comb_cb.patch
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
|
||||||
|
@@ -121,13 +121,15 @@ static inline void ath9k_hw_set_clrdmask
|
||||||
|
static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
|
||||||
|
struct ath_hw_antcomb_conf *antconf)
|
||||||
|
{
|
||||||
|
- ath9k_hw_ops(ah)->antdiv_comb_conf_get(ah, antconf);
|
||||||
|
+ if (ath9k_hw_ops(ah)->antdiv_comb_conf_get)
|
||||||
|
+ ath9k_hw_ops(ah)->antdiv_comb_conf_get(ah, antconf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
|
||||||
|
struct ath_hw_antcomb_conf *antconf)
|
||||||
|
{
|
||||||
|
- ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf);
|
||||||
|
+ if (ath9k_hw_ops(ah)->antdiv_comb_conf_set)
|
||||||
|
+ ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Private hardware call ops */
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
|
||||||
|
@@ -570,8 +570,10 @@ void ar9002_hw_attach_phy_ops(struct ath
|
||||||
|
priv_ops->compute_pll_control = ar9002_hw_compute_pll_control;
|
||||||
|
priv_ops->do_getnf = ar9002_hw_do_getnf;
|
||||||
|
|
||||||
|
- ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
|
||||||
|
- ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
|
||||||
|
+ if (AR_SREV_9285(ah)) {
|
||||||
|
+ ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
|
||||||
|
+ ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
ar9002_hw_set_nf_limits(ah);
|
||||||
|
}
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
|
||||||
|
@@ -1283,8 +1283,10 @@ void ar9003_hw_attach_phy_ops(struct ath
|
||||||
|
priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
|
||||||
|
priv_ops->set_radar_params = ar9003_hw_set_radar_params;
|
||||||
|
|
||||||
|
- ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
|
||||||
|
- ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
|
||||||
|
+ if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) {
|
||||||
|
+ ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
|
||||||
|
+ ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
ar9003_hw_set_nf_limits(ah);
|
||||||
|
ar9003_hw_set_radar_conf(ah);
|
179
package/mac80211/patches/583-ath9k_antenna_control.patch
Normal file
179
package/mac80211/patches/583-ath9k_antenna_control.patch
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/init.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/init.c
|
||||||
|
@@ -652,9 +652,22 @@ static void ath9k_init_txpower_limits(st
|
||||||
|
ah->curchan = curchan;
|
||||||
|
}
|
||||||
|
|
||||||
|
+void ath9k_reload_chainmask_settings(struct ath_softc *sc)
|
||||||
|
+{
|
||||||
|
+ if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
|
||||||
|
+ setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
|
||||||
|
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
|
||||||
|
+ setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
|
||||||
|
{
|
||||||
|
- struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
|
+ struct ath_hw *ah = sc->sc_ah;
|
||||||
|
+ struct ath_common *common = ath9k_hw_common(ah);
|
||||||
|
|
||||||
|
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
|
||||||
|
IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
|
||||||
|
@@ -692,6 +705,17 @@ void ath9k_set_hw_capab(struct ath_softc
|
||||||
|
hw->sta_data_size = sizeof(struct ath_node);
|
||||||
|
hw->vif_data_size = sizeof(struct ath_vif);
|
||||||
|
|
||||||
|
+ hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1;
|
||||||
|
+ hw->wiphy->available_antennas_tx = BIT(ah->caps.max_txchains) - 1;
|
||||||
|
+
|
||||||
|
+ /* single chain devices with rx diversity */
|
||||||
|
+ if (ah->caps.max_rxchains == 1 &&
|
||||||
|
+ ath9k_hw_ops(ah)->antdiv_comb_conf_get)
|
||||||
|
+ hw->wiphy->available_antennas_rx = 3;
|
||||||
|
+
|
||||||
|
+ sc->ant_rx = hw->wiphy->available_antennas_rx;
|
||||||
|
+ sc->ant_tx = hw->wiphy->available_antennas_tx;
|
||||||
|
+
|
||||||
|
#ifdef CONFIG_ATH9K_RATE_CONTROL
|
||||||
|
hw->rate_control_algorithm = "ath9k_rate_control";
|
||||||
|
#endif
|
||||||
|
@@ -703,12 +727,7 @@ void ath9k_set_hw_capab(struct ath_softc
|
||||||
|
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
|
||||||
|
&sc->sbands[IEEE80211_BAND_5GHZ];
|
||||||
|
|
||||||
|
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
|
||||||
|
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ)
|
||||||
|
- setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
|
||||||
|
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
|
||||||
|
- setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
|
||||||
|
- }
|
||||||
|
+ ath9k_reload_chainmask_settings(sc);
|
||||||
|
|
||||||
|
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
|
||||||
|
}
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
|
||||||
|
@@ -652,6 +652,7 @@ struct ath_softc {
|
||||||
|
struct ath_descdma txsdma;
|
||||||
|
|
||||||
|
struct ath_ant_comb ant_comb;
|
||||||
|
+ u32 ant_tx, ant_rx;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ath9k_tasklet(unsigned long data);
|
||||||
|
@@ -673,6 +674,7 @@ int ath9k_init_device(u16 devid, struct
|
||||||
|
const struct ath_bus_ops *bus_ops);
|
||||||
|
void ath9k_deinit_device(struct ath_softc *sc);
|
||||||
|
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
|
||||||
|
+void ath9k_reload_chainmask_settings(struct ath_softc *sc);
|
||||||
|
|
||||||
|
void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
|
||||||
|
bool ath9k_uses_beacons(int type);
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/main.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/main.c
|
||||||
|
@@ -262,6 +262,22 @@ static bool ath_complete_reset(struct at
|
||||||
|
ath_start_ani(common);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (ath9k_hw_ops(ah)->antdiv_comb_conf_get && sc->ant_rx != 3) {
|
||||||
|
+ struct ath_hw_antcomb_conf div_ant_conf;
|
||||||
|
+ u8 lna_conf;
|
||||||
|
+
|
||||||
|
+ ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
|
||||||
|
+
|
||||||
|
+ if (sc->ant_rx == 1)
|
||||||
|
+ lna_conf = ATH_ANT_DIV_COMB_LNA1;
|
||||||
|
+ else
|
||||||
|
+ lna_conf = ATH_ANT_DIV_COMB_LNA2;
|
||||||
|
+ div_ant_conf.main_lna_conf = lna_conf;
|
||||||
|
+ div_ant_conf.alt_lna_conf = lna_conf;
|
||||||
|
+
|
||||||
|
+ ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
ieee80211_wake_queues(sc->hw);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
@@ -2360,6 +2376,59 @@ static int ath9k_get_stats(struct ieee80
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static u32 fill_chainmask(u32 cap, u32 new)
|
||||||
|
+{
|
||||||
|
+ u32 filled = 0;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; cap && new; i++, cap >>= 1) {
|
||||||
|
+ if (!(cap & BIT(0)))
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ if (new & BIT(0))
|
||||||
|
+ filled |= BIT(i);
|
||||||
|
+
|
||||||
|
+ new >>= 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return filled;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
|
||||||
|
+{
|
||||||
|
+ struct ath_softc *sc = hw->priv;
|
||||||
|
+ struct ath_hw *ah = sc->sc_ah;
|
||||||
|
+
|
||||||
|
+ if (!rx_ant || !tx_ant)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ sc->ant_rx = rx_ant;
|
||||||
|
+ sc->ant_tx = tx_ant;
|
||||||
|
+
|
||||||
|
+ if (ah->caps.rx_chainmask == 1)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ /* AR9100 runs into calibration issues if not all rx chains are enabled */
|
||||||
|
+ if (AR_SREV_9100(ah))
|
||||||
|
+ ah->rxchainmask = 0x7;
|
||||||
|
+ else
|
||||||
|
+ ah->rxchainmask = fill_chainmask(ah->caps.rx_chainmask, rx_ant);
|
||||||
|
+
|
||||||
|
+ ah->txchainmask = fill_chainmask(ah->caps.tx_chainmask, tx_ant);
|
||||||
|
+ ath9k_reload_chainmask_settings(sc);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
|
||||||
|
+{
|
||||||
|
+ struct ath_softc *sc = hw->priv;
|
||||||
|
+
|
||||||
|
+ *tx_ant = sc->ant_tx;
|
||||||
|
+ *rx_ant = sc->ant_rx;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
struct ieee80211_ops ath9k_ops = {
|
||||||
|
.tx = ath9k_tx,
|
||||||
|
.start = ath9k_start,
|
||||||
|
@@ -2386,4 +2455,6 @@ struct ieee80211_ops ath9k_ops = {
|
||||||
|
.tx_frames_pending = ath9k_tx_frames_pending,
|
||||||
|
.tx_last_beacon = ath9k_tx_last_beacon,
|
||||||
|
.get_stats = ath9k_get_stats,
|
||||||
|
+ .set_antenna = ath9k_set_antenna,
|
||||||
|
+ .get_antenna = ath9k_get_antenna,
|
||||||
|
};
|
||||||
|
--- a/drivers/net/wireless/ath/ath9k/recv.c
|
||||||
|
+++ b/drivers/net/wireless/ath/ath9k/recv.c
|
||||||
|
@@ -1956,7 +1956,7 @@ int ath_rx_tasklet(struct ath_softc *sc,
|
||||||
|
ath_rx_ps(sc, skb);
|
||||||
|
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
|
||||||
|
|
||||||
|
- if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
|
||||||
|
+ if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3)
|
||||||
|
ath_ant_comb_scan(sc, &rs);
|
||||||
|
|
||||||
|
ieee80211_rx(hw, skb);
|
Loading…
Reference in a new issue