2011-08-29 05:54:34

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH v2 1/4] ath9k: eliminate common->{rx,tx}_chainmask

we already have ah->{rx,tx}chainmask for the same purpose

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath.h | 3 ---
drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 4 ++--
drivers/net/wireless/ath/ath9k/beacon.c | 2 +-
drivers/net/wireless/ath/ath9k/debug.c | 20 ++++++++++----------
drivers/net/wireless/ath/ath9k/htc_drv_init.c | 7 ++-----
drivers/net/wireless/ath/ath9k/htc_drv_main.c | 3 +--
drivers/net/wireless/ath/ath9k/hw.c | 5 ++---
drivers/net/wireless/ath/ath9k/init.c | 9 ++-------
drivers/net/wireless/ath/ath9k/main.c | 7 +++----
drivers/net/wireless/ath/ath9k/xmit.c | 8 ++++----
10 files changed, 27 insertions(+), 41 deletions(-)

diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 17c4b56..f6b77c2 100644
--- 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;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
index f80d1d6..bb2214f 100644
--- 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(struct ath_hw *ah)
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(struct ath_hw *ah)
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;
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 086c9c8..0c757c9 100644
--- 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_softc *sc, struct ath_vif *avp,
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);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index e1f1a96..4062e077 100644
--- 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(struct file *file, char __user *user_buf,
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(struct file *file, const char __user *use
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(struct file *file, const char __user *use
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(struct file *file, char __user *user_buf,
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(struct file *file, const char __user *use
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(struct file *file, const char __user *use
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;
}

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 9cf42f6..966661c 100644
--- 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_htc_priv *priv,
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_htc_priv *priv)
{
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;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 0248024..379f6ba 100644
--- 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_struct *work)
if (longcal || shortcal)
common->ani.caldone =
ath9k_hw_calibrate(ah, ah->curchan,
- common->rx_chainmask,
- longcal);
+ ah->rxchainmask, longcal);

ath9k_htc_ps_restore(priv);
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 3ccadeb..d63f9c8 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1470,9 +1470,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
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;

@@ -2086,6 +2083,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)

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;

diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index d7761d1..31ef501 100644
--- 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_softc *sc,

/* 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_softc *sc)
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(struct ath_softc *sc, int band)
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)
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 7ac1c21..085ec20 100644
--- 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 ath_softc *sc)
{
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 ath_softc *sc)
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_struct *work)
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 data)
if (longcal || shortcal) {
common->ani.caldone =
ath9k_hw_calibrate(ah, ah->curchan,
- common->rx_chainmask, longcal);
+ ah->rxchainmask, longcal);
}

ath9k_ps_restore(sc);
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 68066c5..49b93c2 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1633,7 +1633,7 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)

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;
@@ -1693,7 +1693,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
/* 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))
@@ -1718,10 +1718,10 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
}

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);
--
1.7.3.2



2011-08-29 07:41:28

by Rajkumar Manoharan

[permalink] [raw]
Subject: Re: [PATCH v2 4/4] ath9k: implement .get_antenna and .set_antenna

On Mon, Aug 29, 2011 at 07:54:22AM +0200, Felix Fietkau wrote:
> On MIMO chips this can be used to enable/disable hardware chains, ensuring
> that the MCS information is updated accordingly.
> On non-MIMO chips with rx diversity (e.g. 9285), this configures the rx
> input antenna.
>
> Signed-off-by: Felix Fietkau <[email protected]>
> ---
> drivers/net/wireless/ath/ath9k/ath9k.h | 2 +
> drivers/net/wireless/ath/ath9k/init.c | 33 ++++++++++++---
> drivers/net/wireless/ath/ath9k/main.c | 71 ++++++++++++++++++++++++++++++++
> drivers/net/wireless/ath/ath9k/recv.c | 2 +-
> 4 files changed, 100 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
> index 5d9a9aa..6c7b27c 100644
> --- a/drivers/net/wireless/ath/ath9k/ath9k.h
> +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
> @@ -647,6 +647,7 @@ struct ath_softc {
> struct ath_descdma txsdma;
>
> struct ath_ant_comb ant_comb;
> + u32 ant_tx, ant_rx;
u8 is sufficient.
> };
>
> void ath9k_tasklet(unsigned long data);
> @@ -668,6 +669,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
> 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);
> diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
> index 31ef501..263bbe2 100644
> --- 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(struct ath_softc *sc)
> 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 *sc, struct ieee80211_hw *hw)
> 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;
> +
Why dont you use caps.tx/rx_chainmask instead?
> + /* 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;
> +
Use hw caps to determine ant_divsersity.
use hex instead of decimal for available_antennas, ant_rx/tx
> + 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 *sc, struct ieee80211_hw *hw)
> 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);
> }
> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
> index 4b1fe7c..1cbbaea 100644
> --- 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 ath_softc *sc, bool start)
> 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);
Adjust the fast_div_bias based on main and alt lna conf.
> + }
> +
> ieee80211_wake_queues(sc->hw);
>
> return true;
> @@ -2358,6 +2374,59 @@ static int ath9k_get_stats(struct ieee80211_hw *hw,
> 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);
Setting chainmask alone is not sufficient. dont you have to complete rx and
calibration before setting antenna?
> +
> + 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,
> @@ -2384,4 +2453,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,
> };
> diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
> index ad5f9bd..7e1265c 100644
> --- 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, int flush, bool hp)
> 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);
What about already received packets using combined antennas?
>
> ieee80211_rx(hw, skb);

--
Rajkumar

2011-08-29 05:54:33

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH v2 4/4] ath9k: implement .get_antenna and .set_antenna

On MIMO chips this can be used to enable/disable hardware chains, ensuring
that the MCS information is updated accordingly.
On non-MIMO chips with rx diversity (e.g. 9285), this configures the rx
input antenna.

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/ath9k.h | 2 +
drivers/net/wireless/ath/ath9k/init.c | 33 ++++++++++++---
drivers/net/wireless/ath/ath9k/main.c | 71 ++++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/recv.c | 2 +-
4 files changed, 100 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5d9a9aa..6c7b27c 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -647,6 +647,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);
@@ -668,6 +669,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
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);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 31ef501..263bbe2 100644
--- 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(struct ath_softc *sc)
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 *sc, struct ieee80211_hw *hw)
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 *sc, struct ieee80211_hw *hw)
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);
}
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 4b1fe7c..1cbbaea 100644
--- 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 ath_softc *sc, bool start)
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;
@@ -2358,6 +2374,59 @@ static int ath9k_get_stats(struct ieee80211_hw *hw,
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,
@@ -2384,4 +2453,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,
};
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index ad5f9bd..7e1265c 100644
--- 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, int flush, bool hp)
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);
--
1.7.3.2


2011-08-29 05:54:33

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH v2 2/4] ath9k: merge reset related functions

reduces unnecessary code duplication

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/main.c | 246 ++++++++++++--------------------
1 files changed, 92 insertions(+), 154 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 085ec20..4b1fe7c 100644
--- 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(struct ath_softc *sc)
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;
+ ret = ath_drain_all_txq(sc, retry_tx);

- /* XXX: do not flush receive queue here. We don't want
- * to flush data frames already in queue because of
- * changing channel. */
-
- if (!stopped || !(sc->sc_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, bool start)
+{
+ 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,
@@ -296,21 +252,87 @@ static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
ath9k_hw_set_interrupts(ah, ah->imask);
ath9k_hw_enable_interrupts(ah);

- if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
+ if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) {
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, true))
+ 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_softc *sc, struct ieee80211_hw *hw)
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, true);

/* 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 *sc, struct ieee80211_hw *hw)
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 *sc, struct ieee80211_hw *hw)

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 retry_tx)
}
}

- 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_hw *hw)
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_hw *hw)

/* 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, false)) {
+ 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) {
--
1.7.3.2


2011-08-29 05:54:33

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH v2 3/4] ath9k: only fill antenna diversity hw ops on chips that support it

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9002_phy.c | 6 ++++--
drivers/net/wireless/ath/ath9k/ar9003_phy.c | 6 ++++--
drivers/net/wireless/ath/ath9k/hw-ops.h | 6 ++++--
3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index 3cbbb03..38e91f8 100644
--- 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_hw *ah)
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);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 33edb56..e837792 100644
--- 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_hw *ah)
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);
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index dd9003e..530ed33 100644
--- 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(struct ath_hw *ah, void *ds, bool val)
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 */
--
1.7.3.2


2011-08-29 06:19:25

by Rajkumar Manoharan

[permalink] [raw]
Subject: Re: [PATCH v2 3/4] ath9k: only fill antenna diversity hw ops on chips that support it

On Mon, Aug 29, 2011 at 07:54:21AM +0200, Felix Fietkau wrote:
> Signed-off-by: Felix Fietkau <[email protected]>
> ---
> drivers/net/wireless/ath/ath9k/ar9002_phy.c | 6 ++++--
> drivers/net/wireless/ath/ath9k/ar9003_phy.c | 6 ++++--
> drivers/net/wireless/ath/ath9k/hw-ops.h | 6 ++++--
> 3 files changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
> index 3cbbb03..38e91f8 100644
> --- 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_hw *ah)
> 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;
> + }
>
Better to return from ar900*_hw_antdiv_comb_conf_set/get based on
hw capability (ATH9K_HW_CAP_ANT_DIV_COMB) rathar than adding chip specific
checks. That looks to be more generic.

--
Rajkumar

2011-08-29 07:49:24

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH v2 4/4] ath9k: implement .get_antenna and .set_antenna

On 2011-08-29 9:41 AM, Rajkumar Manoharan wrote:
> On Mon, Aug 29, 2011 at 07:54:22AM +0200, Felix Fietkau wrote:
>> On MIMO chips this can be used to enable/disable hardware chains, ensuring
>> that the MCS information is updated accordingly.
>> On non-MIMO chips with rx diversity (e.g. 9285), this configures the rx
>> input antenna.
>>
>> Signed-off-by: Felix Fietkau<[email protected]>
>> ---
>> drivers/net/wireless/ath/ath9k/ath9k.h | 2 +
>> drivers/net/wireless/ath/ath9k/init.c | 33 ++++++++++++---
>> drivers/net/wireless/ath/ath9k/main.c | 71 ++++++++++++++++++++++++++++++++
>> drivers/net/wireless/ath/ath9k/recv.c | 2 +-
>> 4 files changed, 100 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
>> index 5d9a9aa..6c7b27c 100644
>> --- a/drivers/net/wireless/ath/ath9k/ath9k.h
>> +++ b/drivers/net/wireless/ath/ath9k/ath9k.h
>> @@ -647,6 +647,7 @@ struct ath_softc {
>> struct ath_descdma txsdma;
>>
>> struct ath_ant_comb ant_comb;
>> + u32 ant_tx, ant_rx;
> u8 is sufficient.
>> };
>>
>> void ath9k_tasklet(unsigned long data);
>> @@ -668,6 +669,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc,
>> 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);
>> diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
>> index 31ef501..263bbe2 100644
>> --- 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(struct ath_softc *sc)
>> 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 *sc, struct ieee80211_hw *hw)
>> 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;
>> +
> Why dont you use caps.tx/rx_chainmask instead?
Because rx/tx chainmask can contain odd values such as 0x5, which is
exposed to the user as 0x3 instead.

>> + /* 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;
>> +
> Use hw caps to determine ant_divsersity.
Sure.

> use hex instead of decimal for available_antennas, ant_rx/tx
I think I'll use BIT(0)|BIT(1) instead, as hex values don't really
clarify things either.

>> + 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 *sc, struct ieee80211_hw *hw)
>> 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);
>> }
>> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
>> index 4b1fe7c..1cbbaea 100644
>> --- 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 ath_softc *sc, bool start)
>> 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);
> Adjust the fast_div_bias based on main and alt lna conf.
The fast_div_bias should be irrelevant if there's only one active LNA path.

>> + }
>> +
>> ieee80211_wake_queues(sc->hw);
>>
>> return true;
>> @@ -2358,6 +2374,59 @@ static int ath9k_get_stats(struct ieee80211_hw *hw,
>> 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);
> Setting chainmask alone is not sufficient. dont you have to complete rx and
> calibration before setting antenna?
The antenna is only configured while the interface is down. The main
chipset that has issues with rx chainmask and calibration is AR9100 and
that part is taken care of above.

>> +
>> + 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,
>> @@ -2384,4 +2453,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,
>> };
>> diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
>> index ad5f9bd..7e1265c 100644
>> --- 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, int flush, bool hp)
>> 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);
> What about already received packets using combined antennas?
What do you mean? sc->ant_rx does not change while the interface is up.

- Felix